Promise本意是承諾,在程序中的意思就是承諾我過一段時間後會給你一個結果。javascript
ES6 中採用了 Promise/A+ 規範,Promise 實現以前,固然要先了解 Promise/A+ 規範,規範地址https://promisesaplus.com/。java
咱們根據 Promise/A+ 規範,能夠寫一個簡單的Promise庫。npm
每一步都儘可能寫的詳細,因此代碼很長很羅嗦。數組
使用例子
let Promise = require('./Promise'); // Promise是一個類,須要傳遞一個executor函數,這個函數咱們稱之爲執行函數,函數中有兩個參數resolve和reject他們也是函數,調用resolve表示成功,調用reject表示失敗 let promise = new Promise(function(resolve,reject){ // 成功就不會再調用失敗,默認狀態是等待狀態pending resolve('ok'); reject('faild'); }); // then是原型上的一個方法接收兩個參數分別是成功的回調和失敗的回調 promise.then(function(data){// 調用resolve後會執行成功的回調,調用reject後會執行失敗的回調 console.log(data); },function(err){ console.log(err); });
實現對應的Promise庫代碼
function Promise(executor) { // Promise中須要接收一個執行函數executor let self = this; self.status = 'pending'; //默認是pending狀態 self.value = undefined; // 成功的緣由 self.reason = undefined; // 失敗的緣由 function resolve(value) { // 調用resolve 會傳入爲何成功 if(self.status === 'pending'){ // 只有再pending才能轉換成功態 self.value = value; // 將成功的緣由保存下來 self.status = 'resolved'; // 狀態改爲成功態 } } function reject(reason) { // 調用reject會傳入爲何失敗 if(self.status === 'pending'){ self.reason = reason; self.status = 'rejected'; } } try { executor(resolve, reject);// executor中須要傳入resolve和reject } catch (e) { // 若是executor執行發生異常,表示當前的promise是失敗態 reject(e); } } // then中要傳入成功的回調和失敗的回調 Promise.prototype.then = function(onFufilled,onRejected){ let self = this; // 若是要是成功就調用成功的回調,並將成功的值傳入 if(self.status === 'resolved'){ onFufilled(self.value); } if(self.status === 'rejected'){ onRejected(self.reason); } } module.exports = Promise
在new Promise時內部能夠寫異步代碼,而且產生的實例能夠then屢次promise
使用例子
let Promise = require('./Promise'); let promise = new Promise(function(resolve,reject){ setTimeout(function(){ resolve('ok'); },1000) }); // 當調用then時可能狀態依然是pending狀態,咱們須要將then中的回調函數保留起來,當調用resolve或者reject時按照順序執行 promise.then(function(data){ console.log(data); },function(err){ console.log(err); }); promise.then(function(data){ console.log(data); },function(err){ console.log(err); });
實現對應的Promise庫代碼
function Promise(executor) { self.status = 'pending'; self.value = undefined; self.reason = undefined; + self.onResolvedCallbacks = []; // 成功回調存放的地方 + self.onRejectedCallbacks = [];// 失敗回調存放的地方 function resolve(value) { if(self.status === 'pending'){ self.value = value; self.status = 'resolved'; + // 依次執行成功的回調 + self.onResolvedCallbacks.forEach(item=>item()); } } function reject(reason) { if(self.status === 'pending'){ self.reason = reason; self.status = 'rejected'; + // 依次執行失敗的回調 + self.onRejectedCallbacks.forEach(item=>item()); } } } Promise.prototype.then = function(onFufilled,onRejected){ if(self.status === 'rejected'){ onRejected(self.reason); } + if(self.status === 'pending'){ + // 若是是等待態,就將成功和失敗的回調放到數組中 + self.onResolvedCallbacks.push(function(){ + onFufilled(self.value); + }); + self.onRejectedCallbacks.push(function(){ + onRejected(self.reason); + }); + } }
執行回調中異步
因此寫一個resolvePromise方法,這是promise中最重要的方法,用來解析then返回的結果函數
使用例子
promise.then(function(data){ throw Error('出錯了');// 當前promise已經成功了,成功就不會再失敗 return 'renee' }).then(null,function(err){ // 若是返回的是同一個promise那麼還怎麼走向失敗呢?因此必需要返回一個新的promise console.log(err); })
實現對應的Promise庫代碼
Promise.prototype.then = function(onFufilled,onRejected){ let self = this; + let promise2; // promise2爲then調用後返回的新promise // 若是要是成功就調用成功的回調,並將成功的值傳入 if(self.status === 'resolved'){ - onFufilled(self.value); + promise2 = new Promise(function(resolve,reject){ + try{ + // 執行時有異常發生,須要將promise2的狀態置爲失敗態 + let x = onFufilled(self.value); + // x爲返回的結果 + // 寫一個方法resolvePromise,是對當前返回值進行解析,經過解析讓promise2的狀態轉化成成功態仍是失敗態 + resolvePromise(promise2,x,resolve,reject); + }catch(e){ + reject(e); + } + }) } if(self.status === 'rejected'){ - onRejected(self.reason); + promise2 = new Promise(function(resolve,reject){ + try{ + let x = onRejected(self.reason); + resolvePromise(promise2,x,resolve,reject); + }catch(e){ + reject(e) + } + }) } if(self.status === 'pending'){ + promise2 = new Promise(function(resolve,reject){ self.onResolvedCallbacks.push(function(){ - onFufilled(self.value); + try{ + let x = onFufilled(self.value); + resolvePromise(promise2,x,resolve,reject) + }catch(e){ + reject(e); + } + }) }); self.onRejectedCallbacks.push(function(){ - onRejected(self.reason); + try{ + let x = onRejected(self.reason); + resolvePromise(promise2,x,resolve,reject) + }catch(e){ + reject(e); + } }); + }) } + return promise2; }
function resolvePromise(promise2, x, resolve, reject) { //x是返回的結果,若是promise和then中返回的promise是同一個,是不科學的,要報錯 if(promise2===x){ return reject(new Error('循環引用')) } if(x!==null&&(typeof x === 'object'|| typeof x === 'function')){ let called; //表示是否調用過成功或者失敗 try{ let then=x.then; //若是then是函數,說明是promise,咱們要讓promise執行 if(typeof then==='function'){ then.call(x,function(y){ if(called)return; //若是調用過直接return called=true; //若是resolve的結果依舊是promise那就繼續解析 },function(err){ if(called) return; called=true; reject(err) }) }else{//若是不是函數,x是一個普通的對象,直接成功便可 resolve(x) } }catch(e){ if(called) return; called=true; reject(e); } }else{ //是普通值直接調用成功 resolve(x); } }
使用例子
promise.then().then().then(function(data){ console.log(data) })
實現對應的Promise庫代碼
Promise.prototype.then = function (onFufilled, onRejected) { //失敗和成功默認不傳給一個函數 + onFufilled = typeof onFufilled === 'function'?onFufilled:function(value){ + return value + } + onRejected = typeof onRejected === 'function'?onRejected:function(err){ + throw err + }
另外能夠經過安裝一個插件來對實現的promise進行規範測試。測試
npm(cnpm) i -g promises-aplus-tests promises-aplus-tests 文件名