摘要:本意是承諾,在程序中的意思就是承諾我過一段時間后會給你一個結(jié)果。中采用了規(guī)范,實現(xiàn)之前,當然要先了解規(guī)范,規(guī)范地址。我們根據(jù)規(guī)范,可以寫一個簡單的庫。每一步都盡量寫的詳細,所以代碼很長很羅嗦。
Promise本意是承諾,在程序中的意思就是承諾我過一段時間后會給你一個結(jié)果。
ES6 中采用了 Promise/A+ 規(guī)范,Promise 實現(xiàn)之前,當然要先了解 Promise/A+ 規(guī)范,規(guī)范地址https://promisesaplus.com/。
我們根據(jù) Promise/A+ 規(guī)范,可以寫一個簡單的Promise庫。
每一步都盡量寫的詳細,所以代碼很長很羅嗦。
1.實現(xiàn)Promise基本的方法Promise是一個類,需要傳遞一個executor函數(shù),函數(shù)里有兩個參數(shù)resolve和reject,調(diào)用resolve代表成功,調(diào)用reject代表失敗
Promise有三種狀態(tài):默認狀態(tài)是等待狀態(tài)pending,成功resolved,失敗rejected
使用例子
let Promise = require("./Promise"); // Promise是一個類,需要傳遞一個executor函數(shù),這個函數(shù)我們稱之為執(zhí)行函數(shù),函數(shù)中有兩個參數(shù)resolve和reject他們也是函數(shù),調(diào)用resolve表示成功,調(diào)用reject表示失敗 let promise = new Promise(function(resolve,reject){ // 成功就不會再調(diào)用失敗,默認狀態(tài)是等待狀態(tài)pending resolve("ok"); reject("faild"); }); // then是原型上的一個方法接收兩個參數(shù)分別是成功的回調(diào)和失敗的回調(diào) promise.then(function(data){// 調(diào)用resolve后會執(zhí)行成功的回調(diào),調(diào)用reject后會執(zhí)行失敗的回調(diào) console.log(data); },function(err){ console.log(err); });
實現(xiàn)對應(yīng)的Promise庫代碼
function Promise(executor) { // Promise中需要接收一個執(zhí)行函數(shù)executor let self = this; self.status = "pending"; //默認是pending狀態(tài) self.value = undefined; // 成功的原因 self.reason = undefined; // 失敗的原因 function resolve(value) { // 調(diào)用resolve 會傳入為什么成功 if(self.status === "pending"){ // 只有再pending才能轉(zhuǎn)換成功態(tài) self.value = value; // 將成功的原因保存下來 self.status = "resolved"; // 狀態(tài)改成成功態(tài) } } function reject(reason) { // 調(diào)用reject會傳入為什么失敗 if(self.status === "pending"){ self.reason = reason; self.status = "rejected"; } } try { executor(resolve, reject);// executor中需要傳入resolve和reject } catch (e) { // 如果executor執(zhí)行發(fā)生異常,表示當前的promise是失敗態(tài) reject(e); } } // then中要傳入成功的回調(diào)和失敗的回調(diào) Promise.prototype.then = function(onFufilled,onRejected){ let self = this; // 如果要是成功就調(diào)用成功的回調(diào),并將成功的值傳入 if(self.status === "resolved"){ onFufilled(self.value); } if(self.status === "rejected"){ onRejected(self.reason); } } module.exports = Promise2.異步Promise
在new Promise時內(nèi)部可以寫異步代碼,并且產(chǎn)生的實例可以then多次
用兩個數(shù)組存放成功和失敗的回調(diào),當調(diào)用的時候再執(zhí)行
使用例子
let Promise = require("./Promise"); let promise = new Promise(function(resolve,reject){ setTimeout(function(){ resolve("ok"); },1000) }); // 當調(diào)用then時可能狀態(tài)依然是pending狀態(tài),我們需要將then中的回調(diào)函數(shù)保留起來,當調(diào)用resolve或者reject時按照順序執(zhí)行 promise.then(function(data){ console.log(data); },function(err){ console.log(err); }); promise.then(function(data){ console.log(data); },function(err){ console.log(err); });
實現(xiàn)對應(yīng)的Promise庫代碼
function Promise(executor) { self.status = "pending"; self.value = undefined; self.reason = undefined; + self.onResolvedCallbacks = []; // 成功回調(diào)存放的地方 + self.onRejectedCallbacks = [];// 失敗回調(diào)存放的地方 function resolve(value) { if(self.status === "pending"){ self.value = value; self.status = "resolved"; + // 依次執(zhí)行成功的回調(diào) + self.onResolvedCallbacks.forEach(item=>item()); } } function reject(reason) { if(self.status === "pending"){ self.reason = reason; self.status = "rejected"; + // 依次執(zhí)行失敗的回調(diào) + self.onRejectedCallbacks.forEach(item=>item()); } } } Promise.prototype.then = function(onFufilled,onRejected){ if(self.status === "rejected"){ onRejected(self.reason); } + if(self.status === "pending"){ + // 如果是等待態(tài),就將成功和失敗的回調(diào)放到數(shù)組中 + self.onResolvedCallbacks.push(function(){ + onFufilled(self.value); + }); + self.onRejectedCallbacks.push(function(){ + onRejected(self.reason); + }); + } }3.Promise鏈式調(diào)用
如果當前promise已經(jīng)進入成功的回調(diào),回調(diào)中發(fā)生了異常返回this的話,那么當前的promise的狀態(tài)無法更改到失敗臺!所以promise實現(xiàn)鏈式調(diào)用,返回的并不是this而是一個新的promise。
執(zhí)行回調(diào)中
如果返回的是一個普通的值,會將結(jié)果傳入下一次then的成功回調(diào)中
如果發(fā)生錯誤會被下一次then的失敗回調(diào)捕獲
如果返回的是promise看這個promise是成功還是失敗,對應(yīng)調(diào)用下一次的then
所以寫一個resolvePromise方法,這是promise中最重要的方法,用來解析then返回的結(jié)果
有些人可能成功失敗同時調(diào)用,如果兩個都調(diào)用,用第一個調(diào)用的,不允許同時調(diào)用。
使用例子
promise.then(function(data){ throw Error("出錯了");// 當前promise已經(jīng)成功了,成功就不會再失敗 return "renee" }).then(null,function(err){ // 如果返回的是同一個promise那么還怎么走向失敗呢?所以必須要返回一個新的promise console.log(err); })
實現(xiàn)對應(yīng)的Promise庫代碼
Promise.prototype.then = function(onFufilled,onRejected){ let self = this; + let promise2; // promise2為then調(diào)用后返回的新promise // 如果要是成功就調(diào)用成功的回調(diào),并將成功的值傳入 if(self.status === "resolved"){ - onFufilled(self.value); + promise2 = new Promise(function(resolve,reject){ + try{ + // 執(zhí)行時有異常發(fā)生,需要將promise2的狀態(tài)置為失敗態(tài) + let x = onFufilled(self.value); + // x為返回的結(jié)果 + // 寫一個方法resolvePromise,是對當前返回值進行解析,通過解析讓promise2的狀態(tài)轉(zhuǎn)化成成功態(tài)還是失敗態(tài) + 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是返回的結(jié)果,如果promise和then中返回的promise是同一個,是不科學的,要報錯 if(promise2===x){ return reject(new Error("循環(huán)引用")) } if(x!==null&&(typeof x === "object"|| typeof x === "function")){ let called; //表示是否調(diào)用過成功或者失敗 try{ let then=x.then; //如果then是函數(shù),說明是promise,我們要讓promise執(zhí)行 if(typeof then==="function"){ then.call(x,function(y){ if(called)return; //如果調(diào)用過直接return called=true; //如果resolve的結(jié)果依舊是promise那就繼續(xù)解析 },function(err){ if(called) return; called=true; reject(err) }) }else{//如果不是函數(shù),x是一個普通的對象,直接成功即可 resolve(x) } }catch(e){ if(called) return; called=true; reject(e); } }else{ //是普通值直接調(diào)用成功 resolve(x); } }4.值的穿透
在規(guī)范中定義then函數(shù)可以不傳參,不傳參默認會將成功的結(jié)果和失敗的結(jié)果繼續(xù)向下傳遞
使用例子
promise.then().then().then(function(data){ console.log(data) })
實現(xiàn)對應(yīng)的Promise庫代碼
Promise.prototype.then = function (onFufilled, onRejected) { //失敗和成功默認不傳給一個函數(shù) + onFufilled = typeof onFufilled === "function"?onFufilled:function(value){ + return value + } + onRejected = typeof onRejected === "function"?onRejected:function(err){ + throw err + }5.測試
另外可以通過安裝一個插件來對實現(xiàn)的promise進行規(guī)范測試。
npm(cnpm) i -g promises-aplus-tests promises-aplus-tests 文件名
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/93498.html
摘要:本文同時也發(fā)布在我的博客上,歡迎之前也手寫過簡單的,這次則是為了通過官方的測試集,借鑒了一些下載量較多的,改了幾遍,終于是通過了規(guī)范的個測試用例如何測試測試庫地址在這,大家在寫完自己的后,不妨也去測試一下,檢驗自己的是否符合規(guī)范。 本文同時也發(fā)布在我的github博客上,歡迎star~ 之前也手寫過簡單的promise,這次則是為了通過官方的Promise A+測試集,借鑒了一些下載量...
摘要:如何寫一個符合規(guī)范的實現(xiàn)前言是異步編程的一種解決方案從語法上講,是一個對象,從它可以獲取異步操作的消息從本意上講,它是承諾,承諾它過一段時間會給你一個結(jié)果。 如何寫一個符合promiseA+規(guī)范的promise實現(xiàn) 前言 Promise 是異步編程的一種解決方案:從語法上講,promise是一個對象,從它可以獲取異步操作的消息;從本意上講,它是承諾,承諾它過一段時間會給你一個結(jié)果。pr...
摘要:今天我們來自己手寫一個符合規(guī)范的庫。是異步編程的一種解決方案,比傳統(tǒng)的解決方案回調(diào)函數(shù)和事件更合理和更強大。我們可以看到,其實就是一個構(gòu)造函數(shù)。所以說我們的數(shù)組里存的是一個一個的的回調(diào)函數(shù),也就是一個一個。 今天我們來自己手寫一個符合PromiseA+規(guī)范的Promise庫。大家是不是很激動呢?? showImg(https://segmentfault.com/img/bV6t4Z?...
摘要:以上代碼,可以完美通過所有用例。在的函數(shù)中,為何需要這個同樣是因為規(guī)范中明確表示因此我們需要這樣的來確保只會執(zhí)行一次。其他情況,直接返回以該值為成功狀態(tài)的對象。 Promise是前端面試中的高頻問題,我作為面試官的時候,問Promise的概率超過90%,據(jù)我所知,大多數(shù)公司,都會問一些關(guān)于Promise的問題。如果你能根據(jù)PromiseA+的規(guī)范,寫出符合規(guī)范的源碼,那么我想,對于面試...
摘要:,異步編程的流行解決方案,相比于古老的回調(diào)函數(shù)等方式,它更科學,更優(yōu)雅。它來自民間,后被官方招安。實現(xiàn)方法,方法和狀態(tài)機制根據(jù)使用方法我們可以知道,是一個需要接受一個執(zhí)行器的構(gòu)造函數(shù),執(zhí)行器提供兩個方法,內(nèi)部有狀態(tài)機制,原型鏈上有方法。 Promise,js異步編程的流行解決方案,相比于古老的回調(diào)函數(shù)等方式,它更科學,更優(yōu)雅。它來自民間,后被官方招安。 本文將從介紹用法開始,一步步了解...
閱讀 1788·2023-04-25 20:16
閱讀 4131·2021-10-09 09:54
閱讀 2838·2021-09-04 16:40
閱讀 2593·2019-08-30 15:55
閱讀 904·2019-08-29 12:37
閱讀 2829·2019-08-26 13:55
閱讀 2978·2019-08-26 11:42
閱讀 3242·2019-08-23 18:26