Promise 是什么
ECMAscript 6 原生提供了 Promise 對象。MDN上關(guān)于Promise是這么解釋的:
Promise 對象用于表示一個異步操作的最終完成 (或失敗)及其結(jié)果值。
Promise 狀態(tài)
一個Promise通常有以下幾種狀態(tài)
- pending(待定):初始狀態(tài),既不是成功也不是失敗。
- fulfilled(已兌現(xiàn)、成功):操作成功。
- rejected(已拒絕、失敗):操作失敗。
待定pending狀態(tài)的 Promise 對象要么會通過一個值被兌現(xiàn)(fulfilled),要么會通過一個原因(錯誤)被拒絕(rejected)。
鏈式調(diào)用
對于一個Promise,常用的做法是將 Promise.then(),Promise.catch() 和 Promise.finally()這些方法將進一步的操作與一個變?yōu)橐亚枚顟B(tài)的 Promise關(guān)聯(lián)起來。

以以下代碼舉例:
const p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('operate in promise');
// resolve將Promise狀態(tài)標記為fulfilled,此后執(zhí)行Promise.then中的回調(diào)函數(shù),其中參數(shù)1可以被then中的回調(diào)函數(shù)接收
resolve(1);
// reject方法將Promise狀態(tài)標記為rejected
// reject(new Error(someError))
}, 1000);
});
p.then((result) => {
// Promise狀態(tài)變?yōu)閞ejected后,執(zhí)行異常處理回調(diào)函數(shù)
// 其中參數(shù)result為上面resolve方法的參數(shù):1
console.log('promise fulfilled, return value: ', result);
}).catch((err) => {
// Promise狀態(tài)變?yōu)閞ejected后,執(zhí)行異常處理回調(diào)函數(shù)
// 其中err為reject方法的參數(shù)
console.log('promise rejected', err);
}).finally(() => {
// 成功或異常處理完成后,執(zhí)行finally中的回調(diào)函數(shù)
console.log('finally.')
});
上面的例子中,執(zhí)行結(jié)果如下:

通常的做法是上例中的形式,即p.then(() => {}).catch(() => {}).finally(() => {}),不過查閱MDN文檔發(fā)現(xiàn),鏈式調(diào)用除了上面的形式,還有這樣的形式,即將成功處理和失敗處理同放于then的回調(diào)函數(shù)中,如下:
p.then((result) => {
// handle fulfilled
}, (err) => {
// handle rejected
})
這種形式在寫法上和上面的形式有點區(qū)別,但是作用是一樣的,就不展開描述。
多個Promise調(diào)用
多個Promise并發(fā)調(diào)用
多個Promise并發(fā)執(zhí)行可以借助Promise.all()方法執(zhí)行,該方法返回一個 Promise 實例。方法定義如下:
Promise.all<T>(values: Iterable<T | PromiseLike<T>>): Promise<T[]>;
是待多個Promise全部返回成功狀態(tài)時,才將Promise狀態(tài)標記為成功fullfilled,只要有任何一個Promise返回失敗狀態(tài),狀態(tài)則被標記為失敗rejected,在可以在MDN查看Promise.all()方法的解釋:Promise.all()
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log(11);
resolve(11);
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log(22);
resolve(22);
}, 1000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log(33);
resolve(44);
}, 1000)
})
Promise.all([p1, p2, p3]).then(results => {
// p1,p2,p3中全部成功后執(zhí)行
console.log('all resolved: ', results)
}).catch((err) => {
// p1,p2,p3中只要有一個失敗,執(zhí)行catch方法
console.log('promise rejected', err);
});
執(zhí)行結(jié)果如下:
多個Promise串行調(diào)用
對于多個Promise實例對象p1、p2、p3,如果需要串行執(zhí)行,即先執(zhí)行p1,成功后執(zhí)行p2,再成功后執(zhí)行p3,主要借助于Promise.then()。實例代碼:
const p1 = (preResult) => {
// preResult為前一個Promise返回值,由于p1之前沒有Promise,此處為undefined
return new Promise((resolve, reject) => {
console.log('pre return value: ', preResult);
resolve(11)
});
}
const p2 = (preResult) => {
// preResult為前一個Promise返回值,此處即p1的返回值11
return new Promise((resolve, reject) => {
console.log('pre return value: ', preResult);
resolve(22)
});
}
const p3 = (preResult) => {
// preResult為前一個Promise返回值,此處即p2的返回值22
return new Promise((resolve, reject) => {
console.log('pre return value: ', preResult);
resolve(33)
});
}
p1().then(p2).then(p3).then((result) => {
// result為鏈式調(diào)用中最后一個Promise的返回值,此處為p3返回值33
console.log('last return value: ', result);
})

不確定數(shù)目的Promise的串行調(diào)用
對于上面兩個例子中,Promise數(shù)量都是固定的,調(diào)用起來非常方便,當然對于Promise.all方式調(diào)用,可以調(diào)用任意個數(shù)量的Promise,只要傳進來的參數(shù)是個數(shù)組就可以。但是對于串行調(diào)用,即p1().then(p2).then(p3).then((result) => {})的形式,如果Promise數(shù)量不是固定的,就無法通過枚舉的形式一個一個列出來加到then中進行調(diào)用。
此時我們可以借助于Array.reduce()進行串行調(diào)用,Array.reduce()方法通常用于數(shù)組的累加求和,方法定義如下:
interface Array<T> {
/**
* Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
* @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
* @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
*/
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
}
其中第一個參數(shù)callbackfn為回調(diào)函數(shù),第二個參數(shù)initialValue非必須,為初始值。Array.reduce 可以處理數(shù)組中的每一個元素,并將處理后的結(jié)果作為參數(shù)傳遞給下一個處理函數(shù)。這樣,我們可以在callbackfn中構(gòu)造一個Promise,并傳遞給下一個處理函數(shù)。
const arr = [];
const p1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(new Date());
resolve();
}, 1000)
})
}
arr.push(p1);
const p2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(new Date());
resolve();
// resolve();
}, 1000)
})
}
arr.push(p2);
const p3 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(new Date());
resolve();
}, 1000)
})
}
arr.push(p3);
// 可以在數(shù)組arr中添加其他Promise...
arr.reduce((prev, curv) => {
return prev.then(() => {
return curv().then()
})
}, Promise.resolve()).then(() => {
console.log('all resolved');
}).catch(err => {
console.log('error');
console.error(err);
});
執(zhí)行結(jié)果如下:
可以看到上面的例子中,多個Promise依次串行執(zhí)行,每個Promise在上個Promise執(zhí)行完成后再執(zhí)行。
當然實際上Promise串行執(zhí)行的引用遠遠不止這么簡單,在此不展開來講解。
文章來源:
https://blog.csdn.net/m0_58016522/article/details/119443440