摘要:前言中的異步,剛開始的時候都是用回調函數實現的,所以如果異步嵌套的話,就有出現回調地獄,使得代碼難以閱讀和難以維護,后來出現了,解決了回調地獄的問題。
前言
js中的異步,剛開始的時候都是用回調函數實現的,所以如果異步嵌套的話,就有出現回調地獄,使得代碼難以閱讀和難以維護,后來es6出現了promise,解決了回調地獄的問題。現在我們就自己寫代碼實現一下promise,這樣才能深入理解promise的運行機制,對以后使用promise也能夠更加得心應手。開始之前可以先看下promise的官網
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是如何做到鏈式調用的?
promise中有個狀態機的概念,先說下為什么要有狀態機的概念呢,因為promise的狀態是單向變化的,有三種狀態,pending,fullfilled,rejected,而這三種狀態只能從pending->fullfilled或者pending->rejected這兩種形式,也就是說執行了fullfilled之后,就不會執行rejected。這就解釋了上面的第一個問題。
下面我們來看下具體實現的完整代碼
const PENDING = "PENDING"; const FULLFILLED = "FULLFILLED"; const REJECTED = "REJECTED"; class Promise{ constructor(fn){ this.status = PENDING;//狀態 this.data = undefined;//返回值 this.defercb = [];//回調函數數組 //執行promise的參數函數,并把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對象,這樣就可以保證鏈式調用了 switch(this.status){ case PENDING: return new Promise((resolve,reject)=>{ const onFullFilled = () => { const result = resolveThen(this.data);//這里調用外部then的resolveThen方法,將值傳回去 //如果返回值是promise對象,執行then方法,取它的結果作為新的promise實例的結果,因為this.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; } } }
運行下面的例子
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
說明上面的實現是沒有問題的
不過還有一個問題,就是事件循環的順序問題,比如執行下面的代碼
new Promise((resolve) => { resolve(); }) .then(() => { console.log("1"); }) .then(() => { console.log("2"); }); console.log("3");
并沒有像預想中輸出3,1,2,而是輸出了1,2,3,原因就是因為我們的這個Promise是在主線程中,沒有在下一個任務隊列中,可以加上settimeout解決這個問題,不過這也只是為了讓我們更好理解執行順序而已,然而實際上是promise是屬于微任務中的,而settimeout是屬于宏任務,還是不太一樣的
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99315.html
摘要:有一個和相關的更大的問題。最后,請負有責任感并且使用安全的擴展。深入理解五部曲異步問題深入理解五部曲轉換問題深入理解五部曲可靠性問題深入理解五部曲擴展性問題深入理解五部曲樂高問題最后,安利下我的個人博客,歡迎訪問 原文地址:http://blog.getify.com/promis... 現在,我希望你已經看過深入理解Promise的前三篇文章了。并且假設你已經完全理解Promises...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:簡單的說,即將到來的標準指出是一個,所以作為一個,必須可以被子類化。保護還是子類化這是個問題我真的希望我能創建一個忠實的給及以下。 原文地址:http://blog.getify.com/promis... 如果你需要趕上我們關于Promise的進度,可以看看這個系列前兩篇文章深入理解Promise五部曲--1.異步問題和深入理解Promise五部曲--2.控制權轉移問題。 Promi...
摘要:雖然在后面,但是我先執行繼續看控制臺原來函數返回的是一個對象,如果要獲取到返回值,我們應該用方法,繼續修改代碼。這就是來處理異步。 目前async/await 已經被標準化,我們需要盡快將學習進程提上日程。先說一下async的用法,它作為一個關鍵字放到函數前面,用于表示函數是一個異步函數,因為async就是異步的意思,異步函數也就意味著該函數的執行不會阻塞后面代碼的執行。下面寫一個as...
閱讀 598·2021-11-15 11:38
閱讀 1181·2021-10-11 10:59
閱讀 3495·2021-09-07 09:58
閱讀 485·2019-08-30 15:44
閱讀 3525·2019-08-28 18:14
閱讀 2604·2019-08-26 13:32
閱讀 3517·2019-08-26 12:23
閱讀 2418·2019-08-26 10:59