摘要:源碼參考主要內(nèi)容的迭代設(shè)計(jì)中主要的代碼片段,翻譯一部分加上自己的理解,同時(shí)指出的一些特性。先貼完整代碼安全性和穩(wěn)定性保證和在未來他們被調(diào)用的時(shí)候,應(yīng)該是和注冊(cè)時(shí)的順序是保持一致的。這將顯著降低異步編程中流程控制出錯(cuò)可能性。
源碼參考https://github.com/kriskowal/...promise的雛形主要內(nèi)容:promise的迭代設(shè)計(jì)中主要的代碼片段,翻譯一部分加上自己的理解,同時(shí)指出promise的一些特性。
var maybeOneOneSecondLater = function () { var callback; setTimeout(function () { callback(1); }, 1000); return { then: function (_callback) { callback = _callback; } }; }; maybeOneOneSecondLater().then(callback1);
promise誕生,比起傳統(tǒng)回調(diào),它返回了一個(gè)表示最終結(jié)果的對(duì)象(一個(gè)承諾),我們可以在這個(gè)對(duì)象上調(diào)用函數(shù)觀察它的實(shí)現(xiàn)或者是拒絕。
但本質(zhì)上還是傳入回調(diào),任人宰割。
好的是,promise在異步操作和回調(diào)之間提供了一個(gè)中間層,在這個(gè)中間層里可以搞一些事情,解決傳統(tǒng)回調(diào)的蛋疼問題。
改進(jìn)后的promise可以讓我們的回調(diào)不’任人宰割‘了。
很明顯目前這個(gè)promise只能處理一個(gè)回調(diào),傳入多個(gè)回調(diào)會(huì)覆蓋,所以數(shù)據(jù)結(jié)構(gòu)上應(yīng)該用一個(gè)數(shù)組來儲(chǔ)存回調(diào)函數(shù),需要執(zhí)行的時(shí)候,依次執(zhí)行。
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);
這里對(duì)代碼做一些解釋:
defer函數(shù)的作用:產(chǎn)生promise對(duì)象和resolve函數(shù),可以理解為構(gòu)造函數(shù);
resolve函數(shù)是你在封裝異步函數(shù)時(shí)用的,promise是你使用異步函數(shù)時(shí)用的,defer函數(shù)像是一個(gè)中介,給兩頭服務(wù);
oneOneSecondLater函數(shù)封裝了我們的異步操作setTimeout;
result.resolve():異步操作完成后告訴promise,promise會(huì)替你執(zhí)行回調(diào),這是它作為一個(gè)中介應(yīng)該做的;
oneOneSecondLater().then(callback):oneOneSecondLater函數(shù)的使用者需要告訴promise,成功后執(zhí)行什么;
好了,目前我們的promise可以接受多次回調(diào),并在異步操作完成后順序執(zhí)行了。
第二次改進(jìn)promise這個(gè)中介規(guī)定,異步操作只能成功一次(resove只能調(diào)用一次喲)。
也就是說,使用promise封裝異步操作的同事們不可能讓你的回調(diào)執(zhí)行兩次了。。你就大膽的傳進(jìn)去吧。。
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(); } } } }
補(bǔ)充一點(diǎn):
因?yàn)閜romise在異步操作成功后,就將pending設(shè)為了undefined,這也說明,promise向我們保證了:異步狀態(tài)一旦改變,就定格了。
所以如果一個(gè)異步操作已經(jīng)成功,你再傳回調(diào)進(jìn)去,那就會(huì)直接執(zhí)行:if(pending){pending.push(_callback)}else{_callback();}
第三次改進(jìn):職責(zé)分離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); } } } } }
這個(gè)改進(jìn)就很小了,只是把then封裝到promise對(duì)象中,讓resolve和promise兩個(gè)對(duì)象各司其職;
resolve是在封裝異步操作的時(shí)候用的,promise是在使用異步操作時(shí)候用的;
第四次改進(jìn):加鏈?zhǔn)讲僮?/b>熟悉promise的同學(xué)應(yīng)該知道,每次then執(zhí)行完成后都是會(huì)默認(rèn)返回promis的,就是為了方便鏈?zhǔn)讲僮鳌?br>先貼上完整代碼:
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; } } }; };
直接看是有點(diǎn)懵逼的。。
分開來看一下,先看這一段promise對(duì)象:
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; } }
鏈?zhǔn)讲僮鞯男问剑簒xx.then(callback1).then(callback2)
也就是說我們的then函數(shù)返回的是promise對(duì)象;
所以在then函數(shù)的開始, var result = defer();創(chuàng)建一個(gè)空promise對(duì)象。最后return result;
callback1在執(zhí)行后要把結(jié)果給callback2吧,怎么給呢?
先執(zhí)行回調(diào):callback1(value)
執(zhí)行完了通知下一個(gè)promise可以執(zhí)行了:result.resolve()
合體:result.resolve(callback1(value))
再看這一段resolve函數(shù):
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是封裝者給回調(diào)的參數(shù);
_value可能是一個(gè)promise嗎?當(dāng)然可以;
ref函數(shù)就是為了判斷_vlaue是不是promise,如果是則原樣返回,不是的話包裝成一個(gè)promise返回,方便我們統(tǒng)一處理;
經(jīng)過ref處理過的value肯定是一個(gè)promise了,所以我們統(tǒng)一寫成: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只是作者抽出去的一個(gè)工具函數(shù)哈,其實(shí)不抽的話更容易看懂= =!
把ref合進(jìn)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的一段代碼
增加錯(cuò)誤處理目前來看的話,promise只接受了一個(gè)回調(diào),很明顯這里需要再接受一個(gè)錯(cuò)誤回調(diào),根據(jù)異步操作的執(zhí)行結(jié)果,選擇執(zhí)行哪個(gè)。
先貼完整代碼:
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)); } }; };安全性和穩(wěn)定性
保證callbacks和errbacks在未來他們被調(diào)用的時(shí)候,應(yīng)該是和注冊(cè)時(shí)的順序是保持一致的。這將顯著降低異步編程中流程控制出錯(cuò)可能性。
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; } }; };
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100884.html
摘要:源碼閱讀階段緊接上一篇這次我們開始我們最常用到的部分的源碼解析傳入?yún)?shù)為兩個(gè)函數(shù)和判斷調(diào)用者是否為對(duì)象跳轉(zhuǎn)到了一個(gè)叫做的函數(shù)里面新建一個(gè)對(duì)象傳入函數(shù)傳入給和一個(gè)新的對(duì)象返回新的對(duì)象在這里我們先看看在調(diào)用者不是對(duì)象時(shí)到底做了什么比想象的要簡單 源碼閱讀階段 緊接上一篇,這次我們開始Promise我們最常用到的then部分的源碼解析. then() //傳入?yún)?shù)為兩個(gè)函數(shù),onFulfil...
摘要:參考文檔升級(jí)后的函數(shù)回調(diào)參數(shù)問題中的使用方法和還是不一樣的源碼講解的內(nèi)部機(jī)制優(yōu)化相關(guān)內(nèi)容文章官方文檔簡述使用過的都知道這個(gè)方法的作用,通過該方法會(huì)讓形式的函數(shù)風(fēng)格轉(zhuǎn)換成方法,可以認(rèn)為是一顆語法糖,例如接下來我們就分析一下這個(gè)的內(nèi)部流程。 參考文檔 升級(jí)bluebird 3后Promise.promisify的函數(shù)回調(diào)參數(shù)問題:3中的使用方法和2還是不一樣的 How does Bl...
摘要:源碼閱讀階段先理解根本吧想快點(diǎn)理解的話可以直接跳到下個(gè)標(biāo)題這部分根據(jù)理解將持續(xù)修改空函數(shù)用于判斷傳入構(gòu)造器的函數(shù)是否為空函數(shù)如果為空函數(shù)構(gòu)造一個(gè)對(duì)象并初始化狀態(tài)為終值回調(diào)狀態(tài)和隊(duì)列記錄內(nèi)部最后的一次錯(cuò)誤空對(duì)象標(biāo)識(shí)表示發(fā)生了錯(cuò)誤暴露模塊接口為 源碼閱讀階段 先理解Promise根本吧,想快點(diǎn)理解的話可以直接跳到下個(gè)標(biāo)題.這部分根據(jù)理解將持續(xù)修改. Promise(fn) function...
摘要:回調(diào)隊(duì)列對(duì)象,用于構(gòu)建易于操作的回調(diào)函數(shù)集合,在操作完成后進(jìn)行執(zhí)行。對(duì)象對(duì)象,用于管理回調(diào)函數(shù)的多用途列表。如果傳入一個(gè)延遲對(duì)象,則返回該對(duì)象的對(duì)象,可以繼續(xù)綁定其余回調(diào),在執(zhí)行結(jié)束狀態(tài)之后也同時(shí)調(diào)用其回調(diào)函數(shù)。 在工作中我們可能會(huì)把jQuery選擇做自己項(xiàng)目的基礎(chǔ)庫,因?yàn)槠涮峁┝撕啽愕腄OM選擇器以及封裝了很多實(shí)用的方法,比如$.ajax(),它使得我們不用操作xhr和xdr對(duì)象,直...
摘要:用于延遲執(zhí)行一段代碼,它接受個(gè)參數(shù)回調(diào)函數(shù)和執(zhí)行回調(diào)函數(shù)的上下文環(huán)境,如果沒有提供回調(diào)函數(shù),那么將返回對(duì)象。 instance/index.js function Vue (options) { if (process.env.NODE_ENV !== production && !(this instanceof Vue) ) { warn(Vue is a ...
閱讀 2253·2021-11-18 10:02
閱讀 3501·2021-11-15 11:36
閱讀 1125·2019-08-30 14:03
閱讀 747·2019-08-30 11:08
閱讀 2776·2019-08-29 13:20
閱讀 3300·2019-08-29 12:34
閱讀 1386·2019-08-28 18:30
閱讀 1652·2019-08-26 13:34