Promise 對象用於延遲(deferred) 計算和異步(asynchronous ) 計算。一個Promise對象表明着一個還未完成,但預期未來會完成的操做。app
先來一個例子 A 熟悉下語法異步
var p = new Promise(function(resolve, reject){ console.log('1'); // 運行後續的 callback 列表,例如:then,when等。不然,不會執行then裏面的函數 resolve('go next'); }); // 只考慮成功 p.then(function(){ console.log(2, arguments); return 'next'; }, null).then(function(){ console.log(3, arguments) }, null); // 輸出 1 2 ['go next'] 3 ['next']
最初的設想async
function Promise(func){ // 接收一個函數做爲參數 } Promise.prototype = { then: function(callback){ // 接收函數做爲參數 return this; // 支持鏈式調用 } }
觀察例 A,resolve是一個函數,而且不是用戶傳的,全部Promise自身應該有一個resolve方法,而且這個方法要傳遞給Promise構造器裏面的函數做爲參數。函數
function Promise(func){ // 接收一個函數做爲參數 **func(this.resolve);** } Promise.prototype = { **resolve: function(){ }**, then: function(callback){ // 接收函數做爲參數 return this; // 支持鏈式調用 } }
Promise是按照順序來執行callback的,而且由resolve觸發。測試
function Promise(func){ // 接收一個函數做爲參數 **this.doneList = []; // callback 列表** **func(this.resolve.bind(this)); // 順帶綁定this對象** } Promise.prototype = { resolve: function(){ **//執行回調列表 while(true){ if( this.doneList.length === 0 ){ break; } this.doneList.shift().apply(this); }** }, then: function(callback){ // 接收函數做爲參數 **this.doneList.push(callback); // 加入到回調隊列** return this; // 支持鏈式調用 } }
好,如今寫一個測試用例this
var p =new Promise(function(resolve){ console.log('a'); resolve(); }).then(function(){ console.log('b'); }); // 輸出 'a'
什麼鬼?打印下pspa
console.log(p);
咱們發現原來doneList裏面還有一個函數沒有運行,再運行下這個函數prototype
p.doneList[0].call(this); //結果 console.log('b'); // 打印 b
打斷點跟蹤,發現Promise先執行resolve方法,而後執行then,把函數push到doneList。可是,再也沒有執行過doneList裏面的函數了。怎麼辦呢?咱們能夠給Promise加一個屬性(state)來描述當前狀態,分爲【未完成】(pending)和【完成】(done)。若是執行then時,狀態已是完成態,那麼切換到未完成態,並執行resolve方法。code
function Promise(func){ // 接收一個函數做爲參數 **this.state = 'pending'; // 初始化狀態** this.doneList = []; // callback 列表 func(this.resolve.bind(this)); // 順帶綁定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 = 'pneding'; this.resolve(); } return this; // 支持鏈式調用 } }
用和上面相似的例子再次測試對象
var p =new Promise(function(resolve){ console.log('a'); resolve(); }).then(function(){ console.log('b'); }).then(function(){ console.log('c'); });
結果截圖
這下,咱們自定義的Promise基礎功能完成了最核心的部分了。也許有人會疑問,你這寫的什麼鬼?下面的代碼更簡單,也能實現相同的功能
function Promise(func){ // 接收一個函數做爲參數 func(this.resolve.bind(this)); // 順帶綁定this對象 } Promise.prototype = { resolve: function(){ //什麼也不幹 }, then: function(callback){ // 也是接收函數 callback.call(this); // 直接運行 return this; // 支持鏈式調用 } }
測試用例
var p =new Promise(function(resolve){ console.log('d'); resolve(); }).then(function(){ console.log('e'); }).then(function(){ console.log('f'); });
結果:
可是,文章最前面說過
Promise 對象用於延遲(deferred) 計算和異步(asynchronous ) 計算
而且會順序執行回調列表(doneList)。最終代碼及測試
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; } } var p = new Promise(function(resolve){ window.setTimeout(function(){ console.log('d'); resolve(); }, 1000); }).then(function(){ console.log('e'); }).then(function(){ console.log('f'); }); console.log('被阻塞了嗎?');
輸出:
先輸出'被阻塞了嗎?',一秒鐘後相繼輸出 d、e、f 。能夠看出,不但沒有阻塞後面的代碼執行,並且回調也是按照順序執行的。
結束。
下篇繼續完善,例如數據傳遞以及then中函數返回一個Promise時,如何處理。歡迎你們有疑問或者建議,一塊兒來交流。