promise 是最先由社區提出和實現是一種解決異步編程的方案,比其餘傳統的解決方案(回調函數和事件)更合理和強大。編程
ES6 將其寫進了語言標準,統一了用法,原生提供了 promise 對象。數組
ES6 規定,promise對象是一個構造函數,用來生成 promise 實例。promise
promise是爲解決異步處理回調金字塔問題而產生的緩存
1,promise對象的狀態不受外界影響異步
a,pending 初始狀態異步編程
b,fulfilled 成功狀態函數
c,rejected 失敗狀態this
promise 有以上三種狀態,只有一步操做的結果能夠解決當前是哪種狀態,其餘任何操做都沒法改變這種狀態;spa
2,promise 的狀態一旦改變,就不會再變,任什麼時候候均可以獲得這個結果,狀態不能夠逆,只能由pending 變成fulfilled 或者pending 變成 rejectedprototype
1,沒法取消promise,一旦新建它就會當即執行,沒法中途取消
2,若是不設置回調函數,promise 內部拋出的錯誤,不會反映到外部
3,當處於 pending 狀態時,沒法得知目前進展到了哪個階段,是剛剛開始仍是即將完成
1,onResolvedCallbacks 成功後要執行的回調序列 是一個數組
2,onResolvedCallbacks 失敗後要執行的回調序列 是一個數組
以上兩個數組存放在promise 建立實例時給promise這個類傳的函數中,默認都是空數組。
每次實例 then 的時候 傳入onFulfilled 成功回調 onRejected 失敗回調,若是此時的狀態是pending 則將onFulfilled 和 onRejected push 到對應的成功回調序列數組和失敗回調序列數組中,若是此時的狀態是fulfilled 則 onFulfilled 當即執行,若是此時的狀態是rejected 則 onRejected 當即執行
上述序列中的回調函數執行的時候 是有順序的,即按照順序依次執行
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構造函數接受一個函數做爲參數,該函數的兩個參數分別是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); } }
咱們先來看一個例子,根據例子得出結論,而後再寫源碼的實現部分來驗證結論
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.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數。
//catch原理就是隻傳失敗的回調 Promise.prototype.catch = function(onRejected){ this.then(null,onRejected); }
參數:接受一個數組,數組內都是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狀態。
根據傳入的參數不一樣有不一樣的功能:
值(對象、數組、字符串等):做爲resolve傳遞出去的值
Promise實例:原封不動返回
//返回一個馬上成功的promise //別人提供 給你一個方法,須要你傳入一個promise,但你只有一個普通的值,你就能夠經過這個方法把這個普通的值(string number object)轉成一個promise對象 Promise.resolve = function(value){ return new Promise(function(resolve){ resolve(value); }); }
返回一個Promise實例,這個實例處於reject狀態。
參數通常就是拋出的錯誤信息。
//返回一個馬上失敗的promise Promise.reject = function(reason){ return new Promise(function(resolve,reject){ reject(reason); }); }
參數:接受一個數組,數組內都是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); } }); }