一,promise是什麼? promise 是最早由社區提出和實現是一種解決非同步編程的方案,比其他傳統的解決方案(回調函數和事件)更合理和強大。 ES6 將其寫進了語言標準,統一了用法,原生提供了 promise 對象。 ES6 規定,promise對象是一個構造函數,用來生成 promise 實例 ...
一,promise是什麼?
promise 是最早由社區提出和實現是一種解決非同步編程的方案,比其他傳統的解決方案(回調函數和事件)更合理和強大。
ES6 將其寫進了語言標準,統一了用法,原生提供了 promise 對象。
ES6 規定,promise對象是一個構造函數,用來生成 promise 實例。
二,promise是為解決什麼問題而產生的?
promise是為解決非同步處理回調金字塔問題而產生的
三,promise的兩個特點
1,promise對象的狀態不受外界影響
a,pending 初始狀態
b,fulfilled 成功狀態
c,rejected 失敗狀態
promise 有以上三種狀態,只有一步操作的結果可以解決當前是哪一種狀態,其他任何操作都無法改變這種狀態;
2,promise 的狀態一旦改變,就不會再變,任何時候都可以得到這個結果,狀態不可以逆,只能由pending 變成fulfilled 或者pending 變成 rejected
四,promise的三個缺點
1,無法取消promise,一旦新建它就會立即執行,無法中途取消
2,如果不設置回調函數,promise 內部拋出的錯誤,不會反映到外部
3,當處於 pending 狀態時,無法得知目前進展到了哪一個階段,是剛剛開始還是即將完成
五,promise在哪存放成功回調序列和失敗回調序列?
1,onResolvedCallbacks 成功後要執行的回調序列 是一個數組
2,onResolvedCallbacks 失敗後要執行的回調序列 是一個數組
以上兩個數組存放在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); } }); }