上一篇文章【實現簡易 ES6 Promise 功能 (一)】實現了基本的異步功能。今天咱們接着上次的內容繼續扯,如何實現【數據傳遞】以及當【回調函數返回一個新的promise】segmentfault
上篇已完成的代碼數組
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; } }
測試代碼promise
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裏面的函數做爲參數,以此類推。app
關鍵代碼異步
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 });
結果截圖:
this
今天的第一個功能已經完了,那麼如今開始開發第二個功能。spa
先看一個測試prototype
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; } }
結束。謝謝你們閱讀,若有錯誤或建議請給我留言或者發私信。