編后吐槽:寫的快花眼,很詳細,耐心看必受益匪淺
JavaScript的執行環境是「單線程」的。所謂單線程,是指JS引擎中負責解釋和執行JavaScript代碼的線程只有一個,也就是一次只能完成一項任務,這個任務執行完后才能執行下一個,它會「阻塞」其他任務。這個任務可稱為主線程。但實際上還有其他線程,如事件觸發線程、ajax請求線程等。因為javascript的單線程原理,使得網絡操作,瀏覽器事件,都必須是異步執行的。
* 同步與異步
- 同步:同步模式,即上述所說的單線程模式,一次只能執行一個任務,函數調用后需等到函數執行結束,返回執行的結果,才能進行下一個任務。如果這個任務執行的時間較長,就會導致「線程阻塞」。
var x = true;
while(x);
console.log("don‘t’ carry out");
// javascript 單線程原理導致同步執行,第三步不被執行
- 異步:可以一起執行多個任務,函數調用后不會立即返回執行的結果,如果任務A需要等待,可先執行任務B,等到任務A結果返回后再繼續回調。
// 常見異步,定時器的使用
setTimeout(function() {
console.log('taskA, run as asynchronous');
}, 0)
console.log('taskB, run as synchronize');
//while(true);
// taskB, run as synchronize
// taskA, run as asynchronous
?即使延時時長為0,taskA依舊晚于taskB;因為定時器是異步的,異步任務會在當前腳本所有同步任務完成之后才被執行。,如果同步任務中含有阻塞任務,即放開代碼中的while(true)
,那么taskA將不會被執行。
* 什么是Promise
? 古人云:“君子一諾千金”,這種“承諾某個狀態將來會執行,并且該狀態不會被改變”的對象在JavaScript
中稱為Promise
對象,他是一個構造函數,能將異步的操作以同步的形式表達出來,避免了嵌套地獄(層層嵌套)的發生。它供了統一的API,使得控制異步更加容易
* 回調函數
?回調函數是一段可執行的代碼段,它以「參數」的形式傳遞給其他代碼,在其合適的時間執行這段(回調函數)的代碼。
?異步可以回調,同步也可以回調;
// 同步回調
var func1 = function(cb) {
// ..do something
console.log("before callback");
(cb && typeof(cb) === 'function') && cb();
console.log("after callback");
}
var func2 = function(param) {
// ..do something
var start = new Date();
if(( new Date() - start) < 3000 ){ } // 同步實現延時函數
console.log("I am callback");
}
func1(func2);
------output-------
// before callback
(after 3s...)
// I am callback
// after callback
?由于是同步回調,會阻塞后面的代碼,如果func2是個死循環,后面的代碼就不執行了。為解決這個問題,我們使用異步回調,除了常見的setTimeout
,ajax
也是應用方式之一
// 異步回調
function request(url, param, successFun, errorFunc) {
$.ajax({
type: 'GET',
url: url,
param: param,
async: true, // 默認為true,如果設置為false則變成同步請求
success: successFunc,
error: errorFunc
});
}
request('test.html', '', function(data) {
// 第三個參數為返回成功時執行的函數
console.log('cbData: ', data);
}, function(data) {
// 第四個參數為失敗時的函數
console.log('error: ', error);
});
* 為什么要用Promise
既然已經可以實現異步回調,那我們為什么還要用Promise呢?
javascript代碼
function callback () {
console.log("Done");
}
console.log("before setTimeout()")
setTimeout(callback, 1000);
console.log("after setTimeout()");
控制臺輸出
before setTimeout()
after setTimeout()
(等待一秒后...)
Done
說明: setTimeout()
延時函數時javascript實現異步執行的手段之一,該例中它將callback
放到等待隊列,并且開始為延時量計時,當到達延時量主線程中的事件還沒執行完成,那等待隊列中的事件繼續保持等待,直到主線程的執行完成才被加入到線程中執行。所以代碼中說的”等待一秒后”其實并不準確。
?可見,異步操作會在將來的某個時間點觸發一個函數調用。
?如果我們有這樣一個需求:下一個請求或函數必須要有上一步返回的數據才能執行,如下:
request('test1.html', '', function(data1) {
console.log('第一次請求成功, 這是返回的數據:', data1);
request('test2.html', data1, function (data2) {
console.log('第二次請求成功, 這是返回的數據:', data2);
request('test3.html', data2, function (data3) {
console.log('第三次請求成功, 這是返回的數據:', data3);
//request... 繼續請求
}, function(error3) {
console.log('第三次請求失敗, 這是失敗信息:', error3);
});
}, function(error2) {
console.log('第二次請求失敗, 這是失敗信息:', error2);
});
}, function(error1) {
console.log('第一次請求失敗, 這是失敗信息:', error1);
});
?以上出現了多層回調嵌套,有種暈頭轉向的感覺。這也就是我們常說的厄運回調金字塔(Pyramid of Doom),編程體驗十分不好
? 不僅如此,這種代碼結構,可讀性和可維護性太差,代碼復用率也很低,我們希望能將數據請求和數據處理區分開來,Promise就可以利用then進行「鏈式回調」,將異步操作以同步操作的流程表示出來。
sendRequest('test1.html', '').then(function(data1) {
console.log('第一次請求成功, 這是返回的數據:', data1);
}).then(function(data2) {
console.log('第二次請求成功, 這是返回的數據:', data2);
}).then(function(data3) {
console.log('第三次請求成功, 這是返回的數據:', data3);
}).catch(function(error) {
//用catch捕捉前面的錯誤
console.log('sorry, 請求失敗了, 這是失敗信息:', error);
});
?Promise不僅能以同步的方式表示異步操作,還能catch
到異常,這是ajax
無法實現的
?
* Promise in JS
1. 基本結構
ES6 規定,Promise對象是一個構造函數,用來生成Promise實例。
javascript代碼
var pm = new Promise(function(resolve, reject) {
// ..some code
if( /*異步操作結果*/) {
resolve(value);
} else {
reject(error);
}
})
pm.then(function(){
// handle resolveFunc
},function() {
// handle rejectFunc
})
這就是它的基本模型,為了繼續往下學習,我們需要補充一下Promise的一些基礎知識。
2. Promise 三種狀態
Promise鏈式調用用到resolve
,reject
,then
,catch
,他有以下三種狀態
- pending - 進行中,或者等待中,表示還沒有得到結果
- fulfilled - 已成功,在異步操作成功時調用,并將結果作為參數傳遞出去。
- rejected - 已失敗。在異步操作失敗時調用,并將報出的錯誤作為參數傳遞出去。
?只有異步操作的結果可以決定當前是哪種狀態,其他任何操作都無法改變這個狀態,這也是Promise名字的由來。所謂的“君子一言,駟馬難追”,承諾將來某個狀態,且該狀態不會被其他因素改變。
注釋: 從基本用法的例子中我們看到Promise構造函數的參數是
resolve
和reject
,并不是三種狀態中的fulfilled
和rejected
,原因就是:resolved
表示的是已結束(已定型),它包含fullfilled
和rejected
兩種狀態,但使用中,我們默認的將resolved
當做fulfilled
(成功)使用。
3. Promise 對象的特點
(1)對象的狀態不受外界因素影響。以上已經說過。
(2)一旦結果狀態生成,就不會在改變,任何時候都可以得到這個結果。Promise
對象的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected。只要這兩種狀態發生了,狀態就凝固不變,并一直保持這個結果。就算改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這和事件監聽有很大的區別,事件監聽是實時的,如果錯過了監聽時機,就得不到要監聽的結果了
promise也有缺點
- 無法取消Promise,一旦新建它就會立即執行,無法中途取消
- 如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部(所以健壯的代碼要catch錯誤)
- 當處于pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)
?
* 基本API
1 .then()
語法:
Promise.prototype.then( onFulfilled, onRejected )
這是Promise最常用也是最重要的一個API,他定義了Promise的兩個回調函數,并返回一個新的Promise實例,且返回值傳入這個行Promise的resolve
函數中。
因此,我們可以使用鏈式寫法,如為什么要用Promise中的最后一例,返回的還是一個Promise對象(即有異步操作),這時后一個回調函數,就會等待該Promise對象的狀態發生變化,才會被調用。
2. .catch() - 拋出異常
語法:
Promise.prototype.catch( onRejected )
該方法是.then(undefined, onRejected)
的別名,用于指定發生錯誤時的回調函數。
var promise = new Promise(function(resolve, reject)){
// some code
}
promise.then(function(data) {
console.log('success');
}, function(error) {
conosle.log('error', error)
})
/*---等價于---*/
promise.then(function(data){
console.log('success');
}).catch(function(error) {
consol;e.log('error', error)
})
再看一例
var promise = new Promise(function(resoleve, reject) {
throw new Error('test');
});
// 等同于
var promise = new Promise(resovle, reject) {
reject(new Error('test'));
}
// 以上的reject我們用catch來捕獲
promise.catch(function (error) {
console.log(error);
});
---output---
Error: test
?從上例可以看出,reject
方法的作用,等同于拋錯,這是Promise另一大優勢
?關于Promise拋錯有幾下幾個需要注意的地方
- Promise對象的錯誤,會一直向后傳遞,知道被捕獲,即錯誤總會被下一個catch所捕獲。then方法指定的回調函數,若拋出錯誤,也會被下一個catch捕獲。catch中也能拋錯,則需要后面的catch來捕獲。
sendRequest('test.html').then(function(data1) {
//do something
}).then(function (data2) {
//do something
}).catch(function (error) {
//處理前面三個Promise產生的錯誤
});
- promise狀態一旦改變就會凝固,不會再改變。因此promise一旦fulfilled了,再拋錯,也不會變為rejected,就不會被catch了。
var promise = new Promise(function(resolve, reject) {
resolve();
throw 'error';
});
promise.catch(function(e) {
console.log(e); //This is never called
});
- 如果沒有使用catch方法指定處理錯誤的回調函數,Promise對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應(Chrome會拋錯),這是Promise的另一個缺點。
var promise = new Promise(function(resolve, reject) {
resolve(); // 狀態已經被返回為resolve
throw 'error';
});
promise.catch(function(e) {
console.log(e); //This is never called
});
拋錯實例:
var p = new Promise(function(resolve, reject) {
resolve(x);
});
p.then(function(data){
console.log(data);
});
Chrome上的表現;
? 據說只有chrome會報錯,其他瀏覽器的錯誤不會被捕獲,也不會傳遞到外層代碼,最后沒有任何輸出,promise的狀態也變為rejected
3 .all() - Promise中的“邏輯與”
? 全部執行結束且狀態均為resolve
才為resolve
,有一個執行錯誤,則為reject
語法:
promise.all( iterable )
該方法用于將多個Promise實例,包裝成一個新的Promise實例。
var p = Promise.all([p1, p2, p3]);
Promise.all
方法接受一個數組(或具有Iterator
接口)作參數,數組中的對象(p1、p2、p3)均為promise實例(如果不是一個promise,該項會被用Promise.resolve轉換為一個promise)。它的狀態由這三個promise實例決定。
- 當p1, p2, p3狀態都變為fulfilled,p的狀態才會變為fulfilled,并將三個promise返回的結果,按參數的順序(而不是 resolved的順序)存入數組,傳給p的回調函數
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 3000, "first");
});
var p2 = new Promise(function(resolve, reject) {
resolve("second");
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, "third");
});
Promise.all([p1, p2, p3]).then(function(values) {
console.log(values);
});
// ----output----
// 約3秒后
// ["first", "second", "third"]
- 當p1, p2, p3其中之一狀態變為rejected,p的狀態也會變為rejected,并把第一個被reject的promise的返回值,立即觸發并傳給p的回調函數
// 將上例中的p2適當修改如下
var p2 = new Promise(function(resolve, reject) {
resolve(x);
});
這時,p2會拋出錯誤,立即傳給Promise.all()
,結束執行。
- 這多個 promise 是同時開始、并行執行的,而不是順序執行
4 .race() - 競速執行
? 需要注意的是,它并不是Promise中的“邏輯或”,而是將先結束的傳值給 then
,最先執行完成的是resolve
即resolve
,為reject
則reject
語法:
Promise.race( iterable )
該方法同樣是將多個Promise實例,包裝成一個新的Promise實例。
var p = Promise.race([p1, p2, p3]);
-
Promise.race
方法同樣接受一個數組(或具有Iterator接口)作參數。當p1, p2, p3中有一個實例的狀態發生改變(變為fulfilled或rejected),p的狀態就跟著改變。并把第一個改變狀態的promise的返回值,傳給p的回調函數。
執行resolve
var p1 = new Promise(function(resolve, reject) {
setTimeout(reject, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log('resolve', value);
}, function(error) {
//not called
console.log('reject', error);
});
-------output-------
resolve two
執行reject
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "three");
});
var p4 = new Promise(function(resolve, reject) {
setTimeout(reject, 100, "four");
});
Promise.race([p3, p4]).then(function(value) {
//not called
console.log('resolve', value);
}, function(error) {
console.log('reject', error);
});
-------output-------
reject four
- 在第一個promise對象變為resolve后,并不會取消其他promise對象的執行,如下例
var fastPromise = new Promise(function (resolve) {
setTimeout(function () {
console.log('fastPromise');
resolve('resolve fastPromise');
}, 100);
});
var slowPromise = new Promise(function (resolve) {
setTimeout(function () {
console.log('slowPromise');
resolve('resolve slowPromise');
}, 1000);
});
// 第一個promise變為resolve后程序停止
Promise.race([fastPromise, slowPromise]).then(function (value) {
console.log(value); // => resolve fastPromise
});
-------output-------
fastPromise
resolve fastPromise
slowPromise //仍會執行
5 .resolve() - 立即執行Promise-resolve
語法: 1. Promise.resolve(value); 2. Promise.resolve(promise); 3. Promise.resolve(thenable);
它可以看做new Promise()的快捷方式。
new Promise(function (resolve) {
resolve('Success');
});
//----等同于----
Promise.resolve('Success');
- 這段代碼會讓這個Promise對象立即進入
resolved
狀態,并將結果success
傳遞給then
指定的onFulfilled
回調函數。由于Promise.resolve()
也是返回Promise對象,因此可以用.then()
處理其返回值。
Promise.resolve('success').then(function (value) {
console.log(value);
});
-------output-------
Success
//Resolving an array
Promise.resolve([1,2,3]).then(function(value) {
console.log(value[0]); // => 1
});
//Resolving a Promise
var p1 = Promise.resolve('this is p1');
var p2 = Promise.resolve(p1);
p2.then(function (value) {
console.log(value); // => this is p1
});
-
Promise.resolve()
的另一個作用就是將thenable
對象(即帶有then方法的對象)轉換為Promise對象。
var p1 = Promise.resolve({
then: function (resolve, reject) {
resolve("this is an thenable object!");
}
});
console.log(p1 instanceof Promise); // => true
p1.then(function(value) {
console.log(value); // => this is an thenable object!
}, function(e) {
//not called
});
- 無論是在什么時候拋異常,只要promise狀態變成resolved或rejected,狀態不會再改變,這和新建promise是一樣的。
//在回調函數前拋異常
var p1 = {
then: function(resolve) {
throw new Error("error");
resolve("Resolved");
}
};
var p2 = Promise.resolve(p1);
p2.then(function(value) {
//not called
}, function(error) {
console.log(error); // => Error: error
});
//在回調函數后拋異常
var p3 = {
then: function(resolve) {
resolve("Resolved");
throw new Error("error");
}
};
var p4 = Promise.resolve(p3);
p4.then(function(value) {
console.log(value); // => Resolved
}, function(error) {
//not called
});
6 .reject() - 立即執行Promise-reject
語法:
Promise.reject(reason)
和上述的Promise.resolve()類似,它也是new Promise()的快捷方式。
Promise.reject(new Error('error'));
/*******等同于*******/
new Promise(function (resolve, reject) {
reject(new Error('error'));
});
這段代碼會讓這個Promise對象立即進入rejected狀態,并將錯誤對象傳遞給then指定的onRejected回調函數。
?
* Promise 幾個應用
?Promise
中的.then
方法,可以接收構造函數中處理的狀態的變化,并且分別對應執行。.then
有兩個函數參數,分別接收resolved
和rejected
的執行。
?簡單來說, then
就是定義resolve
和reject
函數的,其resolve
函數相當于:
function resolveFun(data) {
// data 為 promise中resolve函數中所帶的參數
}
?Promise新建后就會立即執行。而then
方法中指定的回調函數,將在當前腳本所有同步任務執行完才會執行。如下例:
1. 執行順序
javascript代碼
var promise = new Promise(function(resolve, reject) {
console.log('before resolved');
resolve();
console.log('after resolved');
});
promise.then(function() {
console.log('resolved');
});
console.log('outer');
-------output-------
// before resolved
// after resolved
// outer
// resolved
2.調用延時執行函數
function timeout (ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done'); // 三個參數?往下看
})
}
timeout(100).then((value) => {
console.log(value)
})
// 輸出 done
?該例寫了一個延時調用函數,設置ms
時間以后,才將Promise的狀態修改為resolve
,然后執行.then
中的打印操作。
?這里埋了個點,比較有意思。當給setTimeout()傳入大于兩個參數時,從第三個開始代表的是傳給延時執行函數的參數,想具體了解的可以戳這里
3. 異步加載圖片
function loadImgAsync (url) {
return new Promise(function (resolve, reject) {
var img = new Image();
image.onload = function () {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
}
image.src = url;
})
}
?上訴的例子中,先加載圖片,如果圖片加載成功,就調用resolve
,否則調用reject
。
4. 用Promise實現一個Ajax操作
var url = 'https://hq.tigerbrokers.com/fundamental/finance_calendar/getType/2017-02-26/2017-06-10';
// 封裝一個get請求的方法
function getJSON(url) {
return new Promise(function(resolve, reject) {
var XHR = new XMLHttpRequest();
XHR.open('GET', url, true);
XHR.send();
XHR.onreadystatechange = function() {
if (XHR.readyState == 4) {
if (XHR.status == 200) {
try {
var response = JSON.parse(XHR.responseText);
resolve(response);
} catch (e) {
reject(e);
}
} else {
reject(new Error(XHR.statusText));
}
}
}
})
}
getJSON(url).then(resp => console.log(resp));
?為了健壯性,處理了很多可能出現的異常,總之,成功了就resolve,失敗了就reject。
?如果調用resolve函數和reject函數時帶有參數,那么它們的參數會被傳遞給回調函數。reject函數的參數通常是Error對象的實例,表示拋出的錯誤;resolve函數的參數除了正常的值以外,還可能是另一個 Promise 實例
現在所有的庫幾乎都將ajax請求利用Promise進行了封裝,因此我們在使用jQuery等庫中的ajax請求時,都可以利用Promise來讓我們的代碼更加優雅和簡單。這也是Promise最常用的一個場景
5. resolve參數為另一個Promise實例 - 難點
var p1 = new Promise(function(resolve, reject) {
// ..some code
})
var p2 = new Promise(function(resolve, reject){
// ..some code
resolve(p1)
})
? 上述中,p1和p2都是一個實例,定義了之后都立即執行,但是p2的resolve方法將p1作為參數,即一個異步操作的結果是返回另一個異步操作
?注意:這時,p1的狀態決定了p2的狀態,如果p1的狀態是pending,那么,p2的回調函數就會等待p1狀態的改變,如果p1的狀態已經是resolve或rejected,那么p2就會立即被執行。
很典型的一個例子
var p1 = new Promise(function(resolve, reject){
setTimeout(() => reject(new Error('Fail')), 3000)
})
var p2 = new Promise(function(resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2.then(result => conosle.log(result))
.catch(error => console.log(error))
// 建議大家看一下瀏覽器輸出效果
// 輸出 Error: fail
分析
?上述代碼中,p1和p2被定義后都立即異步執行,p1執行3秒之后返回reject
,p2執行1秒后返回resolve
,但p2的返回結果是p1,所以,又要等待2秒p1返回結果,即p2的返回結果是“p1的返回結果”,這樣大家就明白了,最終執行的其實是p1的結果reject
,所以p2這里調用.catch
而不是.then
。
?注意:調用resolve
或reject
并不會終結Promise的參數函數的執行。
new Promise(function(resolve, reject) {
resolve(1);
console.log(2);
}).then(val => {
console.log(val)
})
// 2
// 1
?上面代碼中,調用resolve(1)
以后,后面的console.log(2)
還是會執行,并且會首先打印出來。這是因為立即 resolved
的 Promise 是在本輪事件循環的末尾執行,總是晚于本輪循環的同步任務。雖然有這種策略,但我們一般習慣還是將其放在最后。
6. 聊天系統獲取兩個用戶的信息 - Promise.all()
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
// 同時執行p1和p2,并在它們都完成后執行then:
Promise.all([p1, p2]).then(function (results) {
console.log(results); // 獲得一個Array: ['P1', 'P2']
});
7. 多個異步任務提高容錯率 - Promise.race()
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
console.log(result); // 'P1'
});
由于p1
執行較快,Promise的then()
將獲得結果'P1'。p2仍在繼續執行,但執行結果將被丟棄。
* Promise常見問題
到這里,相信你已學會使用Promise了,congratulation!
1. reject 和 catch 的區別
-
promise.then(onFulfilled, onRejected)
在onFulfilled
中發生異常的話,在onRejected
中是捕獲不到這個異常的。 -
promise.then(onFulfilled).catch(onRejected)
.then
中產生的異常能在.catch
中捕獲
綜上所述,建議使用第二種,因為能捕獲之前的所有異常。當然了,第二種的.catch()
也可以使用.then()
的捕錯法表示,它們本質上是沒有區別的,.catch === .then(null, onRejected)
2. 如果在then中拋錯,而沒有對錯誤進行處理(即catch),那么會一直保持reject狀態,直到catch了錯誤
/* 例4.1 */
function taskA() {
console.log(x);
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}
function finalTask() {
console.log("Final Task");
}
var promise = Promise.resolve();
promise
.then(taskA) // 拋出錯誤,不繼續Task A”
.then(taskB) // .then沒有捕獲A拋出的錯,不打印 “Task B”
.catch(onRejected) // 捕獲了A的錯,打印錯誤信息
.then(finalTask); // 錯誤已經被捕獲,執行resolve
-------output-------
Catch Error: A or B,ReferenceError: x is not defined
Final Task
來看一下該例的流程
很明顯,A拋錯時,會按照
taskA → onRejected → finalTask
這個流程來處理。A拋錯后,若沒有對它進行處理,狀態就會維持rejected
,taskB不會執行,直到catch
了錯誤。
3. 每次調用then都會返回一個新創建的promise對象,而then內部只是返回的數據
//方法1:對同一個promise對象同時調用 then 方法
var p1 = new Promise(function (resolve) {
resolve(100);
});
p1.then(function (value) {
return value * 2;
});
p1.then(function (value) {
return value * 2;
});
p1.then(function (value) {
console.log("finally: " + value);
});
-------output-------
finally: 100
then
的調用幾乎是同時開始執行的,且傳給每個then的value都是100,這種方法應當避免。正確的應該是采用鏈式調用。
//方法2:對 then 進行 promise chain 方式進行調用
var p2 = new Promise(function (resolve) {
resolve(100);
});
p2.then(function (value) {
return value * 2;
}).then(function (value) {
return value * 2;
}).then(function (value) {
console.log("finally: " + value);
});
-------output-------
finally: 400
或許上面這個案例你還沒感覺,來看看這個:
function badAsyncCall(data) {
var promise = Promise.resolve(data);
promise.then(function(value) {
//do something
return value + 1;
});
return promise;
}
badAsyncCall(10).then(function(value) {
console.log(value); //想要得到11,實際輸出10
});
-------output-------
10
正確的寫法應該是:
function goodAsyncCall(data) {
var promise = Promise.resolve(data);
return promise.then(function(value) {
//do something
return value + 1;
});
return promise;
}
goodAsyncCall(10).then(function(value) {
console.log(value);
});
-------output-------
11
4. 在異步回調中拋錯,不會被catch到
// Errors thrown inside asynchronous functions will act like uncaught errors
var promise = new Promise(function(resolve, reject) {
setTimeout(function() {
throw 'Uncaught Exception!';
}, 1000);
});
promise.catch(function(e) {
console.log(e); //This is never called
});
5. promise狀態變為resove或reject,就凝固了,不會再改變
console.log(1);
new Promise(function (resolve, reject){
reject();
setTimeout(function (){
resolve(); //not called
}, 0);
}).then(function(){
console.log(2);
}, function(){
console.log(3);
});
console.log(4);
-------output-------
1
4
3
花了兩天工作之余的時間,總算寫完了~~看了很多資源,借鑒了許多觀點和例子,希望能幫到大家
參考資源:
?阮一峰的ES6 教程
?廖雪峰的官方網站
?Promise迷你書
?MDN Promise
廖雪峰的官網能直接在里面自定義代碼嘗試運行,挺有意思。