前言
JS中異步編程主要分爲四種,其中回調和生成器不是這篇文章的重點,本文主要集中在Promise和async, await上面。
Promise
首先我們看Promise的幾個特點:
- 回調函數延遲綁定即then方法,它可以接受兩個回調函數作爲參數。第一個回調函數是Promise對象的狀態變爲resolved時調用,第二個參數可選,一般使用catch觸發,無論那種方式都是把回調函數延遲執行。
- 返回值穿透。
readFilePromise('1.json').then(data => {
return readFilePromise('2.json');
}).then(data => {
return readFilePromise('3.json');
}).then(data => {
return readFilePromise('4.json');
});
可以看到then方法返回的Promise可以在後面繼續使用。
- 錯誤冒泡,整個thenable鏈式調用發生的每一處錯誤都可以由最後一個catch捕獲。
then方法
then毫無疑問是這些方法種最重要的,我學習鏈式調用時下面代碼解答了我很多疑惑。
注意then接收兩個參數,都是函數,第二個可選。
同時函數返回的可以是一個值也可以是一個Promise,如果是前者,他會調用一個Promise包裹傳遞給後面使用;如果是後者同樣也會調用給後面使用。
var p = new Promise(function(resolve, reject){
resolve(1);
});
p.then(function(value){ //第一個then
console.log(value);
return value*2;
}).then(function(value){ //第二個then
console.log(value);
}).then(function(value){ //第三個then
console.log(value);
return Promise.resolve('resolve');
}).then(function(value){ //第四個then
console.log(value);
return Promise.reject('reject');
}).then(function(value){ //第五個then
console.log('resolve: '+ value);
}, function(err){
console.log('reject: ' + err);
})
接着來看一段執行順序的判斷:
var p1 = new Promise( function(resolve,reject){
console.log('start1')
resolve( 1 );
});
p1.then(
function(value){
console.log('p1 then value: ' + value);
}
).then(
function(value){
console.log('p1 then then value: '+value);
}
);
var p2 = new Promise(function(resolve,reject){
resolve( 2 );
});
p2.then(
function(value){
console.log('p2 then value: ' + value);
}
).then(
function(value){
console.log('p2 then then value: ' + value);
}
).then(
function(value){
console.log('p2 then then then value: ' + value);
}
);
console.log('start2')
最後的執行結果爲:
VM382:2 start1
VM382:33 start2
VM382:8 p1 then value: 1
VM382:22 p2 then value: 2
VM382:12 p1 then then value: undefined
VM382:26 p2 then then value: undefined
VM382:30 p2 then then then value: undefined
resolve和reject
關於resolve,它可以接受普通值,也可以接收一個Promise
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
如這一段程序,3000ms之前p1的狀態是pendding,由於這是p2中resolve依賴p1的狀態,所以p2的狀態我們可以忽略了。
這時p2走then方法,result即爲一個Promise,狀態pendding。
3000ms後走catch,這是因爲p1狀態改變,而p2直接轉發了p1的reject。
all和race
一個是都完成纔算成功,一個是誰跑得快誰成功。
當然關於all和race還有一些細節,如傳的是值而不是promise的話會先進行Promise處理;error若在Promise中聲明,是不會走all的catch方法的等等。