摘要:源碼參考主要內容的迭代設計中主要的代碼片段,翻譯一部分加上自己的理解,同時指出的一些特性。先貼完整代碼安全性和穩定性保證和在未來他們被調用的時候,應該是和注冊時的順序是保持一致的。這將顯著降低異步編程中流程控制出錯可能性。
源碼參考https://github.com/kriskowal/...promise的雛形主要內容:promise的迭代設計中主要的代碼片段,翻譯一部分加上自己的理解,同時指出promise的一些特性。
var maybeOneOneSecondLater = function () { var callback; setTimeout(function () { callback(1); }, 1000); return { then: function (_callback) { callback = _callback; } }; }; maybeOneOneSecondLater().then(callback1);
promise誕生,比起傳統回調,它返回了一個表示最終結果的對象(一個承諾),我們可以在這個對象上調用函數觀察它的實現或者是拒絕。
但本質上還是傳入回調,任人宰割。
好的是,promise在異步操作和回調之間提供了一個中間層,在這個中間層里可以搞一些事情,解決傳統回調的蛋疼問題。
改進后的promise可以讓我們的回調不’任人宰割‘了。
很明顯目前這個promise只能處理一個回調,傳入多個回調會覆蓋,所以數據結構上應該用一個數組來儲存回調函數,需要執行的時候,依次執行。
let defer = () => { let pending = [],value; return { resolve(_value){ value = _value for(let i = 0;i < pending.length; i++){ pending[i](value) } pending = undefined; }, then(_callback){ if(pending){ pending.push(_callback) }else{ _callback(); } } } } let oneOneSecondLater = () => { let result = defer(); setTimeout(()=> { result.resolve(1); }, 1000); return result; }; oneOneSecondLater().then(callback);
這里對代碼做一些解釋:
defer函數的作用:產生promise對象和resolve函數,可以理解為構造函數;
resolve函數是你在封裝異步函數時用的,promise是你使用異步函數時用的,defer函數像是一個中介,給兩頭服務;
oneOneSecondLater函數封裝了我們的異步操作setTimeout;
result.resolve():異步操作完成后告訴promise,promise會替你執行回調,這是它作為一個中介應該做的;
oneOneSecondLater().then(callback):oneOneSecondLater函數的使用者需要告訴promise,成功后執行什么;
好了,目前我們的promise可以接受多次回調,并在異步操作完成后順序執行了。
第二次改進promise這個中介規定,異步操作只能成功一次(resove只能調用一次喲)。
也就是說,使用promise封裝異步操作的同事們不可能讓你的回調執行兩次了。。你就大膽的傳進去吧。。
let defer = () => { let pending = [],value return { resolve(_value){ if(pending){ value = _value for(let i = 0;i < pending.length; i++){ pending[i](value) } pending = undefined; }else{ throw new Error("A promise can only be resolved once.") } }, then(_callback){ if(pending){ pending.push(_callback) }else{ _callback(); } } } }
補充一點:
因為promise在異步操作成功后,就將pending設為了undefined,這也說明,promise向我們保證了:異步狀態一旦改變,就定格了。
所以如果一個異步操作已經成功,你再傳回調進去,那就會直接執行:if(pending){pending.push(_callback)}else{_callback();}
第三次改進:職責分離let defer = () => { let pending = [],value; return { resolve(_value){ if(pending){ value = _value for(let i = 0;i < pending.length; i++){ pending[i](value) } pending = undefined; }else{ throw new Error("A promise can only be resolved once.") } }, promise: { then (callback) { if (pending) { pending.push(callback); } else { callback(value); } } } } }
這個改進就很小了,只是把then封裝到promise對象中,讓resolve和promise兩個對象各司其職;
resolve是在封裝異步操作的時候用的,promise是在使用異步操作時候用的;
第四次改進:加鏈式操作熟悉promise的同學應該知道,每次then執行完成后都是會默認返回promis的,就是為了方便鏈式操作。
先貼上完整代碼:
var ref = function (value) { if (value && typeof value.then === "function") return value; return { then: function (callback) { return ref(callback(value)); } }; }; var defer = function () { var pending = [], value; return { resolve: function (_value) { if (pending) { value = ref(_value); // values wrapped in a promise for (var i = 0, ii = pending.length; i < ii; i++) { var callback = pending[i]; value.then(callback); // then called instead } pending = undefined; } }, promise: { then: function (_callback) { var result = defer(); // callback is wrapped so that its return // value is captured and used to resolve the promise // that "then" returns var callback = function (value) { result.resolve(_callback(value)); }; if (pending) { pending.push(callback); } else { value.then(callback); } return result.promise; } } }; };
直接看是有點懵逼的。。
分開來看一下,先看這一段promise對象:
promise: { then: function (_callback) { var result = defer(); // callback is wrapped so that its return // value is captured and used to resolve the promise // that "then" returns var callback = function (value) { result.resolve(_callback(value)); }; if (pending) { pending.push(callback); } else { value.then(callback); } return result.promise; } }
鏈式操作的形式:xxx.then(callback1).then(callback2)
也就是說我們的then函數返回的是promise對象;
所以在then函數的開始, var result = defer();創建一個空promise對象。最后return result;
callback1在執行后要把結果給callback2吧,怎么給呢?
先執行回調:callback1(value)
執行完了通知下一個promise可以執行了:result.resolve()
合體:result.resolve(callback1(value))
再看這一段resolve函數:
resolve: function (_value) { if (pending) { value = ref(_value); // values wrapped in a promise for (var i = 0, ii = pending.length; i < ii; i++) { var callback = pending[i]; value.then(callback); // then called instead } pending = undefined; } },
resolve(_value)中的_value是封裝者給回調的參數;
_value可能是一個promise嗎?當然可以;
ref函數就是為了判斷_vlaue是不是promise,如果是則原樣返回,不是的話包裝成一個promise返回,方便我們統一處理;
經過ref處理過的value肯定是一個promise了,所以我們統一寫成:value.then(callback)
貼一下ref:
var ref = function (value) { if (value && typeof value.then === "function") return value; return { then: function (callback) { return ref(callback(value)); } }; };
這里看到,如果vlaue是promise,就直接返回;
value如果不是promise,包裝成promise,把value傳入callback;
所以ref只是作者抽出去的一個工具函數哈,其實不抽的話更容易看懂= =!
把ref合進resolve,大家看看是不是容易理解了:
resolve: function (_value) { if (pending) { if(_value && typeof _value.then === "function") { for (var i = 0, ii = pending.length; i < ii; i++) { var callback = pending[i]; _value.then(callback); } }else { for (var i = 0, ii = pending.length; i < ii; i++) { pending[i](_value); } } pending = undefined; } },
這種寫法沒有保存_value到value中,僅僅是為了解釋resolve的一段代碼
增加錯誤處理目前來看的話,promise只接受了一個回調,很明顯這里需要再接受一個錯誤回調,根據異步操作的執行結果,選擇執行哪個。
先貼完整代碼:
var defer = function () { var pending = [], value; return { resolve: function (_value) { if (pending) { value = ref(_value); for (var i = 0, ii = pending.length; i < ii; i++) { value.then.apply(value, pending[i]); } pending = undefined; } }, promise: { then: function (_callback, _errback) { var result = defer(); // provide default callbacks and errbacks _callback = _callback || function (value) { // by default, forward fulfillment return value; }; _errback = _errback || function (reason) { // by default, forward rejection return reject(reason); }; var callback = function (value) { result.resolve(_callback(value)); }; var errback = function (reason) { result.resolve(_errback(reason)); }; if (pending) { pending.push([callback, errback]); } else { value.then(callback, errback); } return result.promise; } } }; }; let ref = (value) => { if (value && typeof value.then === "function") return value; return { then: function (callback) { return ref(callback(value)); } }; }; let reject = (reason) => { return { then: function (callback, errback) { return ref(errback(reason)); } }; };安全性和穩定性
保證callbacks和errbacks在未來他們被調用的時候,應該是和注冊時的順序是保持一致的。這將顯著降低異步編程中流程控制出錯可能性。
let enqueue = (callback) => { setTimeout(callback,1) } resolve: function (_value) { if (pending) { value = ref(_value); for (let i = 0, ii = pending.length; i < ii; i++) { enqueue(function () { value.then.apply(value, pending[i]); }); } pending = undefined; } } let ref = function (value) { if (value && value.then) return value; return { then: function (callback) { let result = defer(); // XXX enqueue(function () { result.resolve(callback(value)); }); return result.promise; } }; }; let reject = function (reason) { return { then: function (callback, errback) { var result = defer(); // XXX enqueue(function () { result.resolve(errback(reason)); }); return result.promise; } }; };
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100884.html
摘要:源碼閱讀階段緊接上一篇這次我們開始我們最常用到的部分的源碼解析傳入參數為兩個函數和判斷調用者是否為對象跳轉到了一個叫做的函數里面新建一個對象傳入函數傳入給和一個新的對象返回新的對象在這里我們先看看在調用者不是對象時到底做了什么比想象的要簡單 源碼閱讀階段 緊接上一篇,這次我們開始Promise我們最常用到的then部分的源碼解析. then() //傳入參數為兩個函數,onFulfil...
摘要:參考文檔升級后的函數回調參數問題中的使用方法和還是不一樣的源碼講解的內部機制優化相關內容文章官方文檔簡述使用過的都知道這個方法的作用,通過該方法會讓形式的函數風格轉換成方法,可以認為是一顆語法糖,例如接下來我們就分析一下這個的內部流程。 參考文檔 升級bluebird 3后Promise.promisify的函數回調參數問題:3中的使用方法和2還是不一樣的 How does Bl...
摘要:源碼閱讀階段先理解根本吧想快點理解的話可以直接跳到下個標題這部分根據理解將持續修改空函數用于判斷傳入構造器的函數是否為空函數如果為空函數構造一個對象并初始化狀態為終值回調狀態和隊列記錄內部最后的一次錯誤空對象標識表示發生了錯誤暴露模塊接口為 源碼閱讀階段 先理解Promise根本吧,想快點理解的話可以直接跳到下個標題.這部分根據理解將持續修改. Promise(fn) function...
摘要:回調隊列對象,用于構建易于操作的回調函數集合,在操作完成后進行執行。對象對象,用于管理回調函數的多用途列表。如果傳入一個延遲對象,則返回該對象的對象,可以繼續綁定其余回調,在執行結束狀態之后也同時調用其回調函數。 在工作中我們可能會把jQuery選擇做自己項目的基礎庫,因為其提供了簡便的DOM選擇器以及封裝了很多實用的方法,比如$.ajax(),它使得我們不用操作xhr和xdr對象,直...
摘要:用于延遲執行一段代碼,它接受個參數回調函數和執行回調函數的上下文環境,如果沒有提供回調函數,那么將返回對象。 instance/index.js function Vue (options) { if (process.env.NODE_ENV !== production && !(this instanceof Vue) ) { warn(Vue is a ...
閱讀 2222·2021-11-18 10:02
閱讀 3480·2021-11-15 11:36
閱讀 1116·2019-08-30 14:03
閱讀 725·2019-08-30 11:08
閱讀 2761·2019-08-29 13:20
閱讀 3287·2019-08-29 12:34
閱讀 1375·2019-08-28 18:30
閱讀 1642·2019-08-26 13:34