最新的ES6标準添加有Promise方法,但自己在項目中一直使用jQuery(jQuery自己實作了不标準的Promise),加上es6标準還沒有得到普及,也就懶得學習相關資料。
最近手頭上的活少了,本着好好學習,天天向上的宗旨,便查了些資料,學習下Promise。
我們都知道js是單線程的,意味着在同一時間段,浏覽器隻能解析一段腳本。這很讓人抓狂啊。想想你自己,同一時間隻能吃零食或看電影,不能邊吃零食邊看電影,那得多崩潰啊。
許多時候,我們的業務需求需要保證這樣的資料流向:A->B->C->...>X
基于事件回調,我們可以把事件一層層嵌套,一層層回調。但這很容易導緻回調金字塔。
Promise基于這些類似的業務場景,提供給了我們解決事件回調的方案。
===============================================================
Promise
1.構造一個promise對象
1 var promise = new Promise(function(resolve, reject) {
2 // do a thing, possibly async, then…
3
4 if (/* everything turned out fine */) {
5 resolve("Stuff worked!");
6 }
7 else {
8 reject(Error("It broke"));
9 }
10 });
Promise的構造器接受一個函數作為參數,它會傳遞這個回調函數兩個變量resolve和reject。在回調函數中你可以做一些異步操作,成功之後調用resolve,否則調用reject。
2.Promise的使用
1 promise.then(function(result) {
2 console.log(result); // "Stuff worked!"
3 }, function(err) {
4 console.log(err); // Error: "It broke"
5 });
這裡有兩個回調,第一個回調對應執行個體化Promise時reslove方法,第二個回調則對應reject方法。當然,這兩個函數都是可選的,是否使用基于個人需要。
3.Promise的鍊式調用
Promise強大的地方就在于它不僅可以配平回調金字塔,而且可以鍊式調用,每一次調用then函數,都會傳回一個Promise類。
1 var promise = new Promise(function(resolve, reject) {
2 resolve(1);
3 });
4
5 promise.then(function(val) {
6 console.log(val); // 1
7 return val + 2;
8 }).then(function(val) {
9 console.log(val); // 3
10 });
這裡神奇的地方就在于then函數的傳回。如果你傳回一個值,它就會被傳給下一個then回調;而如果你傳回一個Promise對象,則下一個then就會等待這個Promise明确結束(成功或失敗)才會失敗。
最佳實踐
我們有如下需求,需要首先load到資料1,資料1成功傳回後才繼續load資料2。用Promise來實作,就是下面的代碼,大家可以參考學習下
1 var getData1 = function () {
2 return new Promise(function (resolve, reject) {
3 $.ajax({
4 dataType: "json",
5 url: 'testData1.json',
6 success: function (data) {
7 resolve(data);
8 },
9 error: function (err) {
10 reject(err);
11 }
12 });
13 });
14 }
15 var getData2 = function () {
16 return new Promise(function (resolve, reject) {
17 $.ajax({
18 dataType: "json",
19 url: 'testData2.json',
20 success: function (data) {
21 resolve(data);
22 },
23 error: function (err) {
24 reject(err);
25 }
26 });
27 });
28 }
29 getData1().then(function (res) {
30 console.log('####data1');
31 console.log(res);
32 return getData2();
33 }).then(function (res) {
34 console.log('####data2');
35 console.log(res);
36 });
我把擷取資料1和資料2分成兩個方法來實作。在getData1的then回調中,傳回getData2,這樣就能保證load到資料1再去load資料2.
=================================================================================
Promise确實強大,但可惜的是,現在能支援es6特性的浏覽器不多。很多情況下,原生的Promise不是我們的首選。
上面講到的這些特性隻是一些基本的特性,它還有許多強大的特性需要我們去挖掘。
假以時日,浏覽器端完成統一大戰,ES6得到廣泛支援,那将是前端界的一大幸事,雖然前路漫漫,但我們依舊翹首以待!