一、Promise是什么?
Promise是最早由社區提出和實現的一種解決異步編程的方案,比其他傳統的解決方案(回調函數和事件)更合理和更強大。
ES6 將其寫進了語言標准,統一了用法,原生提供了Promise對象。
ES6 規定,Promise對象是一個構造函數,用來生成Promise實例。
二、Promise是為解決什么問題而產生的?
promise是為解決異步處理回調金字塔問題而產生的
三、Promise的兩個特點
1、Promise對象的狀態不受外界影響
1)pending 初始狀態
2)fulfilled 成功狀態
3)rejected 失敗狀態
Promise 有以上三種狀態,只有異步操作的結果可以決定當前是哪一種狀態,其他任何操作都無法改變這個狀態
2、Promise的狀態一旦改變,就不會再變,任何時候都可以得到這個結果,狀態不可以逆,只能由 pending變成fulfilled或者由pending變成rejected
四、Promise的三個缺點
1)無法取消Promise,一旦新建它就會立即執行,無法中途取消
2)如果不設置回調函數,Promise內部拋出的錯誤,不會反映到外部
3)當處於pending狀態時,無法得知目前進展到哪一個階段,是剛剛開始還是即將完成
五、Promise在哪存放成功回調序列和失敗回調序列?
1)onResolvedCallbacks 成功后要執行的回調序列 是一個數組
2)onRejectedCallbacks 失敗后要執行的回調序列 是一個數組
以上兩個數組存放在Promise 創建實例時給Promise這個類傳的函數中,默認都是空數組。
每次實例then的時候 傳入 onFulfilled 成功回調 onRejected 失敗回調,如果此時的狀態是pending 則將onFulfilled和onRejected push到對應的成功回調序列數組和失敗回調序列數組中,如果此時的狀態是fulfilled 則onFulfilled立即執行,如果此時的狀態是rejected則onRejected立即執行
上述序列中的回調函數執行的時候 是有順序的,即按照順序依次執行
六、Promise的用法
1、Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由 JavaScript 引擎提供,不用自己部署。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 異步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
2、resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去;reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去。
3、Promise實例生成以后,可以用then方法分別指定resolved狀態和rejected狀態的回調函數。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
then方法可以接受兩個回調函數作為參數。第一個回調函數是Promise對象的狀態變為resolved時調用,第二個回調函數是Promise對象的狀態變為rejected時調用。其中,第二個函數是可選的,不一定要提供。這兩個函數都接受Promise對象傳出的值作為參數。
七、按照Promise A+規范寫Promise的簡單實現原理
// 第一步:Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由 JavaScript 引擎提供,不用自己部署。
function Promise(task) {
let that = this; // 緩存this
that.status = 'pending'; // 進行中的狀態
that.value = undefined; //初始值
that.onResolvedCallbacks = []; // 存放成功后要執行的回調函數的序列
that.RejectedCallbacks = []; // 存放失敗后要執行的回調函數的序列
// 該方法是將Promise由pending變成fulfilled
function resolve (value) {
if (that.status == 'pending') {
that.status = 'fulfilled';
that.value = value;
that.onResolvedCallbacks.forEach(cb => cd(that.value))
}
}
// 該方法是將Promise由pending變成rejected
function reject (reason) {
if (that.status == 'pending') {
that.status = 'rejected';
that.value = reason;
that.onRjectedCallbacks.forEach(cb => cd(that.value))
}
}
try {
// 每一個Promise在new一個實例的時候 接受的函數都是立即執行的
task(resolve, reject)
} catch (e) {
reject(e)
}
}
// 第二部 寫then方法,接收兩個函數onFulfilled onRejected,狀態是成功態的時候調用onFulfilled 傳入成功后的值,失敗態的時候執行onRejected,傳入失敗的原因,pending 狀態時將成功和失敗后的這兩個方法緩存到對應的數組中,當成功或失敗后 依次再執行調用
Promise.prototype.then = function(onFulfilled, onRejected) {
let that = this;
if (that.status == 'fulfilled') {
onFulfilled(that.value);
}
if (that.status == 'rejected') {
onRejected(that.value);
}
if (that.status == 'pending') {
that.onResolvedCallbacks.push(onFulfilled);
that.onRjectedCallbacks.push(onRejected);
}
}
八、Promise 鏈式寫法
我們先來看一個例子,根據例子得出結論,然后再寫源碼的實現部分來驗證結論
let promise = new Promise(function (resolve, reject) {
resolve(100);// reject(100)
});
promise.then(function (data) {
return data+100;
},function (err) {
return 'ssss';
}).then(function (data) {
console.log(data);// 200 // undefined // sss
})
從上面的例子可以看出:
當第一個promise的成功的回調里返回 200時,第二個promise的成功回調的參數就是200
當將resolve(100)改成reject(100)的時候,因為失敗回調中什么也沒有返回所以第二個promise的成功回調中的參數是undefined
當失敗的回調中返回sss時,第二個promise的成功回調中的參數是sss
由此我們可以看出,第一個promise不管成功回調還是失敗回調,他的返回值作為第二個promise中的成功時回調函數的參數值
鏈式寫法能一直then下去的原因:鏈式調用靠的是返回新的promise,來保證可以一直走成功或失敗
九、 Promise.catch
Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數。
//catch原理就是只傳失敗的回調
Promise.prototype.catch = function(onRejected){
this.then(null,onRejected);
}
十、 Promise.all 方法
參數:接受一個數組,數組內都是Promise實例
返回值:返回一個Promise實例,這個Promise實例的狀態轉移取決於參數的Promise實例的狀態變化。當參數中所有的實例都處於resolve狀態時,返回的Promise實例會變為resolve狀態。如果參數中任意一個實例處於reject狀態,返回的Promise實例變為reject狀態
Promise.all = function(promises){
return new Promise(function(resolve,reject){
let done = gen(promises.length,resolve);
for(let i=0;i<promises.length;i++){
promises[i].then(function(data){
done(i,data);
},reject);
}
});
}
十一、Promise.resolve
返回一個Promise實例,這個實例處於resolve狀態。
根據傳入的參數不同有不同的功能:
值(對象、數組、字符串等):作為resolve傳遞出去的值
Promise實例:原封不動返回
//返回一個立刻成功的promise
//別人提供 給你一個方法,需要你傳入一個promise,但你只有一個普通的值,你就可以通過這個方法把這個普通的值(string number object)轉成一個promise對象
Promise.resolve = function(value){
return new Promise(function(resolve){
resolve(value);
});
}
十二、 Promise.reject
返回一個Promise實例,這個實例處於reject狀態。
參數一般就是拋出的錯誤信息。
//返回一個立刻失敗的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
});
}
十三、 Promise.race
參數:接受一個數組,數組內都是Promise實例
返回值:返回一個Promise實例,這個Promise實例的狀態轉移取決於參數的Promise實例的狀態變化。當參數中任何一個實例處於resolve狀態時,返回的Promise實例會變為resolve狀態。如果參數中任意一個實例處於reject狀態,返回的Promise實例變為reject狀態。
Promise.race = function(promises){
return new Promise(function(resolve,reject){
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject);
}
});
}
