摘要:前言中的異步,剛開始的時候都是用回調(diào)函數(shù)實(shí)現(xiàn)的,所以如果異步嵌套的話,就有出現(xiàn)回調(diào)地獄,使得代碼難以閱讀和難以維護(hù),后來出現(xiàn)了,解決了回調(diào)地獄的問題。
前言
js中的異步,剛開始的時候都是用回調(diào)函數(shù)實(shí)現(xiàn)的,所以如果異步嵌套的話,就有出現(xiàn)回調(diào)地獄,使得代碼難以閱讀和難以維護(hù),后來es6出現(xiàn)了promise,解決了回調(diào)地獄的問題?,F(xiàn)在我們就自己寫代碼實(shí)現(xiàn)一下promise,這樣才能深入理解promise的運(yùn)行機(jī)制,對以后使用promise也能夠更加得心應(yīng)手。開始之前可以先看下promise的官網(wǎng)
promise/A+
先來看下promise的用法
new Promise((resolve,reject)=>{ resolve(1); reject(11); }).then(res=>{ console.log(res); setTimeout(()=>{ return new Promise((resolve,reject)=>{ resolve(2) }) },1000) }).then(res2=>{ console.log(res2); });
控制臺打印
1
...1s later
2
先分析下上面這段代碼,先提出幾個問題
1.第一段resolve和reject都有,但是只輸出了1,為什么?
2.then里的res是如何取到resolve中的值的?
3.promise是如何做到鏈?zhǔn)秸{(diào)用的?
promise中有個狀態(tài)機(jī)的概念,先說下為什么要有狀態(tài)機(jī)的概念呢,因?yàn)閜romise的狀態(tài)是單向變化的,有三種狀態(tài),pending,fullfilled,rejected,而這三種狀態(tài)只能從pending->fullfilled或者pending->rejected這兩種形式,也就是說執(zhí)行了fullfilled之后,就不會執(zhí)行rejected。這就解釋了上面的第一個問題。
下面我們來看下具體實(shí)現(xiàn)的完整代碼
const PENDING = "PENDING"; const FULLFILLED = "FULLFILLED"; const REJECTED = "REJECTED"; class Promise{ constructor(fn){ this.status = PENDING;//狀態(tài) this.data = undefined;//返回值 this.defercb = [];//回調(diào)函數(shù)數(shù)組 //執(zhí)行promise的參數(shù)函數(shù),并把resolve和reject的this綁定到promise的this fn(this.resolve.bind(this),this.reject.bind(this)); } resolve(value){ if(this.status === PENDING){ //只能pending=>fullfied this.status = FULLFILLED; this.data = value; this.defercb.map(item=>item.onFullFilled()); } } reject(value){ if(this.status === PENDING){ //只能pending=>rejected this.status = REJECTED; this.data = value; this.defercb.map(item=>item.onRejected()); } } then(resolveThen,rejectThen){ //如果沒有resolveThen方法,保證值可以穿透到下一個then里有resolveThen的方法中 resolveThen = typeof resolveThen === "function" ? resolveThen : function(v) {return v}; rejectThen = typeof rejectThen === "function" ? rejectThen : function(r) {return r}; //返回的都是promise對象,這樣就可以保證鏈?zhǔn)秸{(diào)用了 switch(this.status){ case PENDING: return new Promise((resolve,reject)=>{ const onFullFilled = () => { const result = resolveThen(this.data);//這里調(diào)用外部then的resolveThen方法,將值傳回去 //如果返回值是promise對象,執(zhí)行then方法,取它的結(jié)果作為新的promise實(shí)例的結(jié)果,因?yàn)閠his.data會重新賦值 result instanceof Promise && result.then(resolve,reject); } const onRejected = ()=>{ const result = rejectThen(this.data); result instanceof Promise && result.then(resolve,reject); } this.defercb.push({onFullFilled,onRejected}); }); break; case FULLFILLED: return new Promise((resolve,reject)=>{ const result = resolveThen(this.data); result instanceof Promise && result.then(resolve,reject); resolve(result); }) break; case REJECTED: return new Promise((resolve,reject)=>{ const result = rejectThen(this.data); result instanceof Promise && result.then(resolve,reject); reject(result) }) break; } } }
運(yùn)行下面的例子
new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }).then((res2) => { console.log(res2); return new Promise((resolve, reject) => { setTimeout(() => { resolve(2); }, 1000); }); }).then((res3) => { console.log(res3); return new Promise((resolve, reject) => { setTimeout(() => { resolve(3); }, 1000); }); }).then((res4) => { console.log(res4); });
控制臺打印
...1s later
1
...1s later
2
...1s later
3
說明上面的實(shí)現(xiàn)是沒有問題的
不過還有一個問題,就是事件循環(huán)的順序問題,比如執(zhí)行下面的代碼
new Promise((resolve) => { resolve(); }) .then(() => { console.log("1"); }) .then(() => { console.log("2"); }); console.log("3");
并沒有像預(yù)想中輸出3,1,2,而是輸出了1,2,3,原因就是因?yàn)槲覀兊倪@個Promise是在主線程中,沒有在下一個任務(wù)隊(duì)列中,可以加上settimeout解決這個問題,不過這也只是為了讓我們更好理解執(zhí)行順序而已,然而實(shí)際上是promise是屬于微任務(wù)中的,而settimeout是屬于宏任務(wù),還是不太一樣的
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/99315.html
摘要:有一個和相關(guān)的更大的問題。最后,請負(fù)有責(zé)任感并且使用安全的擴(kuò)展。深入理解五部曲異步問題深入理解五部曲轉(zhuǎn)換問題深入理解五部曲可靠性問題深入理解五部曲擴(kuò)展性問題深入理解五部曲樂高問題最后,安利下我的個人博客,歡迎訪問 原文地址:http://blog.getify.com/promis... 現(xiàn)在,我希望你已經(jīng)看過深入理解Promise的前三篇文章了。并且假設(shè)你已經(jīng)完全理解Promises...
摘要:的翻譯文檔由的維護(hù)很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個符合規(guī)范并可配合使用的寫一個符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個需求:在系統(tǒng)初始化時通過http獲取一個第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個接口,可通過...
摘要:簡單的說,即將到來的標(biāo)準(zhǔn)指出是一個,所以作為一個,必須可以被子類化。保護(hù)還是子類化這是個問題我真的希望我能創(chuàng)建一個忠實(shí)的給及以下。 原文地址:http://blog.getify.com/promis... 如果你需要趕上我們關(guān)于Promise的進(jìn)度,可以看看這個系列前兩篇文章深入理解Promise五部曲--1.異步問題和深入理解Promise五部曲--2.控制權(quán)轉(zhuǎn)移問題。 Promi...
摘要:雖然在后面,但是我先執(zhí)行繼續(xù)看控制臺原來函數(shù)返回的是一個對象,如果要獲取到返回值,我們應(yīng)該用方法,繼續(xù)修改代碼。這就是來處理異步。 目前async/await 已經(jīng)被標(biāo)準(zhǔn)化,我們需要盡快將學(xué)習(xí)進(jìn)程提上日程。先說一下async的用法,它作為一個關(guān)鍵字放到函數(shù)前面,用于表示函數(shù)是一個異步函數(shù),因?yàn)閍sync就是異步的意思,異步函數(shù)也就意味著該函數(shù)的執(zhí)行不會阻塞后面代碼的執(zhí)行。下面寫一個as...
閱讀 647·2021-11-15 11:38
閱讀 1366·2021-10-11 10:59
閱讀 3556·2021-09-07 09:58
閱讀 552·2019-08-30 15:44
閱讀 3583·2019-08-28 18:14
閱讀 2664·2019-08-26 13:32
閱讀 3573·2019-08-26 12:23
閱讀 2475·2019-08-26 10:59