摘要:今天我們接著上次的內容繼續扯,如何實現數據傳遞以及當回調函數返回一個新的上篇已完成的代碼測試代碼上面的結果,就是我們要實現的。然后,等到下次需要的時候,再傳給下一個回調函數。先來修改方法,因為回調函數都是在這里運行的。
上一篇文章【實現簡易 ES6 Promise 功能 (一)】實現了基本的異步功能。今天我們接著上次的內容繼續扯,如何實現【數據傳遞】以及當【回調函數返回一個新的promise】
上篇已完成的代碼
function Promise(func){ this.state = "pending"; this.doneList = []; func(this.resolve.bind(this)); } Promise.prototype = { resolve: function(){ while(true){ if( this.doneList.length === 0 ){ this.state = "done"; break; } this.doneList.shift().apply(this); } }, then: function(callback){ this.doneList.push(callback); if( this.state === "done"){ this.state = "pending"; this.resolve(); } return this; } }
測試代碼
new Promise(function(resolve){ resolve(1) }).then(function(data){ console.log(data); // 1 return 2; }).then(function(data){ console.log(data); // 2 });
上面的結果,就是我們要實現的。resolve的參數(只傳遞第一個參數,如果有)傳遞給第一個then里面函數作為參數,第一個then里面的函數返回值傳遞給第二個then里面的函數作為參數,以此類推。
關鍵代碼
resolve: function(){ // arguments[0]是resolve的第一個參數 while(true){ if( this.doneList.length === 0 ){ this.state = "done"; break; } // 這里是運行then里面回調函數的地方 this.doneList.shift().apply(this); } }
如何修改呢?除了第一次傳遞參數,是把resolve的參數往下傳遞,其余的都是把上次的結果作為下次開始(參數)。
于是,我們可以先把上次doneList里面的函數運行結果保存起來。然后,等到下次需要的時候,再傳給下一個回調函數。
代碼修改:
resolve: function(){ // arguments[0]是resolve的第一個參數 var arg = arguments[0]; while(true){ if( this.doneList.length === 0 ){ this.state = "done"; break; } // 這里是運行then里面回調函數的地方 // 以數組形式傳給下一個函數,然后保存新的值 // 判斷傳遞的參數是否為undefined,是的話,就不用傳了 if( typeof arg === "undefined" ){ arg = this.doneList.shift().apply(this); }else{ arg = this.doneList.shift().apply(this, [arg]); } } // 保存最后的arg,保證后續的回調能繼續得到參數 this.arg = arg; } // 還需要修改then方法 then: function(callback){ this.doneList.push(callback); if( this.state === "done"){ this.state = "pending"; this.resolve(this.arg); // 注意這里也要傳遞參數 } return this; }
第一次修改完善的代碼,及測試結果
function Promise(func){ this.state = "pending"; this.doneList = []; func(this.resolve.bind(this)); } Promise.prototype = { resolve: function(){ // arguments[0]是resolve的第一個參數 var arg = arguments[0]; while(true){ if( this.doneList.length === 0 ){ this.state = "done"; break; } // 這里是運行then里面回調函數的地方 // 以數組形式傳給下一個函數,然后保存新的值 // 判斷傳遞的參數是否為undefined,是的話,就不用傳了 if( typeof arg === "undefined" ){ arg = this.doneList.shift().apply(this); }else{ arg = this.doneList.shift().apply(this, [arg]); } } // 保存最后的arg,保證后續的回調能繼續得到參數 this.arg = arg; }, then: function(callback){ this.doneList.push(callback); if( this.state === "done"){ this.state = "pending"; this.resolve(this.arg); // 注意這里也要傳遞參數 } return this; } } // 測試 new Promise(function(resolve){ resolve(1) }).then(function(data){ console.log(data); // 1 return 2; }).then(function(data){ console.log(data); // 2 });
結果截圖:
今天的第一個功能已經完了,那么現在開始開發第二個功能。
先看一個測試
new Promise(function(resolve){ resolve(1) }).then(function(data){ console.log(data, 2); // 1,2 return new Promise(function(resolve){ window.setTimeout(function(){ resolve(3); }, 1000); }).then(function(data){ console.log(data, 4); // 3,4 return 5; }); }).then(function(data){ console.log(data, 6); // 5, 6 });
測試結果
我在上面測試例子中,then回調函數中返回的promise中故意使用了延遲函數。但是,輸出結果中5往后傳了,并且[5,6]是在[3,4]之后,且都有一秒中的延遲。
如果沒有回調返回一個promise,程序會一直按照第一行走下去,就算回調中有其他promise(只要不return),也是兩條并行的線。一旦返回promise,新的promise會在這個點插入,并且原來還沒有執行的回調,也會排到新的回調列表后面了。
先來修改resolve方法,因為回調函數都是在這里運行的。
resolve: function(){ // arguments[0]是resolve的第一個參數 var arg = arguments[0]; while(true){ if( this.doneList.length === 0 ){ this.state = "done"; break; } /*************************/ if( arg instanceof Promise ){ // 把新的promise保存起來,待會要用 this.promise = arg; // 本promise沒有執行完的回調全部加入到新的回調列表 arg.doneList = arg.doneList.concat(this.doneList); // 改變回調及狀態 this.doneList.length = 0; this.state = "done"; // 跳出循環 break; } /*************************/ // 這里是運行then里面回調函數的地方 // 以數組形式傳給下一個函數,然后保存新的值 // 判斷傳遞的參數是否為undefined,是的話,就不用傳了 if( typeof arg === "undefined" ){ arg = this.doneList.shift().apply(this); }else{ arg = this.doneList.shift().apply(this, [arg]); } } // 保存最后的arg,保證后續的回調能繼續得到參數 this.arg = arg; } then: function(callback){ this.doneList.push(callback); if( this.state === "done"){ this.state = "pending"; this.resolve(this.arg); // 注意這里也要傳遞參數 } // 這里不能在返回this了,而是一個promise對象 return this.promise; } // 如果then沒有返回promise,那么this.promise = this; function Promise(func){ this.state = "pending"; this.doneList = []; func(this.resolve.bind(this)); // 默認指向本身 this.promise = this; }
本期完整代碼
function Promise(func){ this.state = "pending"; this.doneList = []; func(this.resolve.bind(this)); this.promise = this; } Promise.prototype = { resolve: function(){ // arguments[0]是resolve的第一個參數 var arg = arguments[0]; while(true){ if( this.doneList.length === 0 ){ this.state = "done"; break; } if( arg instanceof Promise ){ this.promise = arg; arg.doneList = arg.doneList.concat(this.doneList); this.doneList.length = 0; this.state = "done"; break; } // 這里是運行then里面回調函數的地方 // 以數組形式傳給下一個函數,然后保存新的值 // 判斷傳遞的參數是否為undefined,是的話,就不用傳了 if( typeof arg === "undefined" ){ arg = this.doneList.shift().apply(this); }else{ arg = this.doneList.shift().apply(this, [arg]); } } // 保存最后的arg,保證后續的回調能繼續得到參數 this.arg = arg; }, then: function(callback){ this.doneList.push(callback); if( this.state === "done"){ this.state = "pending"; this.resolve(this.arg); // 注意這里也要傳遞參數 } return this.promise; } }
結束。謝謝大家閱讀,如有錯誤或建議請給我留言或者發私信。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78565.html
摘要:對象用于延遲計算和異步計算。一個對象代表著一個還未完成,但預期將來會完成的操作。接收一個函數作為參數接收函數作為參數支持鏈式調用是按照順序來執行的,并且由觸發。下篇繼續完善,例如數據傳遞以及中函數返回一個時,如何處理。 Promise 對象用于延遲(deferred) 計算和異步(asynchronous ) 計算。一個Promise對象代表著一個還未完成,但預期將來會完成的操作。 先...
前言 作為一個后端過來的同學,剛入門前端的時候,被js種種「反人類」的概念折騰的死去活來的.其中一個印象比較深刻的,就是promise,感覺實在太難理解了...所有就有了寫個簡單的promise的想法.希望能幫助到一些跟我一樣,感覺promise很難理解的新同學. promise的教程網上多如牛毛,其中寫的比較通俗易懂的莫過于阮一峰的es6,反正我是他的書才懂的.所以今天,我們也不會來復述一遍如何...
摘要:在處理異步回調函數的情況有著越來越值得推崇的方法及類庫,下面會依次介紹處理異步函數的發展史,及源碼解讀。而對象的狀態,是由第一個的參數成功回調函數或失敗回調函數的返回值決定的。 函數的執行分為同步和異步兩種。同步即為 同步連續執行,通俗點講就是做完一件事,再去做另一件事。異步即為 先做一件事,中間可以去做其他事情,稍后再回來做第一件事情。同時還要記住兩個特性:1.異步函數是沒有返回值的...
摘要:錯過了一周的優質內容,不要再錯過周一的快速回顧一周深度揭秘啟動全過程翻譯組每周社區問答入門語言簡明入門與提高一只爬蟲崔小拽爬蟲知乎用戶數據爬取和分析如何學習開源動效分析二動畫最佳實踐一工具箱之生命周期工具箱之權限管理一步步創建自己的框 錯過了一周的優質內容,不要再錯過周一的快速回顧 一周 fir.im Weekly -《深度揭秘 App 啟動全過程》 SwiftGG翻譯組 -《每周 S...
摘要:錯過了一周的優質內容,不要再錯過周一的快速回顧一周深度揭秘啟動全過程翻譯組每周社區問答入門語言簡明入門與提高一只爬蟲崔小拽爬蟲知乎用戶數據爬取和分析如何學習開源動效分析二動畫最佳實踐一工具箱之生命周期工具箱之權限管理一步步創建自己的框 錯過了一周的優質內容,不要再錯過周一的快速回顧 一周 fir.im Weekly -《深度揭秘 App 啟動全過程》 SwiftGG翻譯組 -《每周 S...
閱讀 2628·2021-11-23 09:51
閱讀 2418·2021-09-30 09:48
閱讀 2044·2021-09-22 15:24
閱讀 1009·2021-09-06 15:02
閱讀 3303·2021-08-17 10:14
閱讀 1934·2021-07-30 18:50
閱讀 1980·2019-08-30 15:53
閱讀 3168·2019-08-29 18:43