摘要:調(diào)用初始的的方法,將匿名函數(shù)和匿名函數(shù)添加到原始的回調(diào)列表。當(dāng)?shù)臓顟B(tài)發(fā)生了改變,相關(guān)的回調(diào)函數(shù)會被執(zhí)行,上面注冊的是的和方法作為的回調(diào)函數(shù),那么的函數(shù)會在的狀態(tài)改變后被執(zhí)行,那么的狀態(tài)就發(fā)生了改變。
Promise實現(xiàn)代碼分析
全是去嘗試?yán)斫鈩e人是怎么實現(xiàn)promise的,感覺下面這兩個鏈接的Promise實現(xiàn)比較好。
實現(xiàn)1 實現(xiàn)2
實現(xiàn)2的配圖以及講解更細(xì)致一點(diǎn),如果能跟著作者舉的例子走一遍,應(yīng)該能夠理解為什么可以then().then().then(),以及理解為啥resolve(Promise)的狀態(tài)為啥是由參數(shù)的promise的狀態(tài)來決定的,也能理解resolve(value)的參數(shù)是如何傳遞給后續(xù)的通過then注冊的function的。但是30分鐘有點(diǎn)少,猶猶豫豫,糾結(jié)得看了好久。
相對而言,實現(xiàn)1的較為完整,實現(xiàn)2的某些東西只是提到了,但是沒提供實現(xiàn)。比如resolve/reject都只能調(diào)用一次。
實現(xiàn)1
function doResolve(fn, onFulfilled, onRejected) { var done = false; try { fn(function (value) { if (done) return done = true onFulfilled(value) }, function (reason) { if (done) return done = true onRejected(reason) }) } catch (ex) { if (done) return done = true onRejected(ex) } }
var promise = new Promise(fn);
fn是創(chuàng)建promise傳入的參數(shù),它是一個function,在創(chuàng)建Promise的過程中需要被調(diào)用。
這個fn有兩個參數(shù),都是function,前面一個是在fn按照得到了正常的結(jié)果之后調(diào)用的,那么then注冊的onfulfilled的方法就會在完成之后調(diào)用。另外一個就是fn遇到了意料之外的結(jié)果,相應(yīng)的就會調(diào)用then注冊的onrejected方法。
doResolve的方法就是讓fn只能調(diào)用一次resolve或者一次reject方法,即只能改變promise的狀態(tài)一次。
this.done = function (onFulfilled, onRejected) { // ensure we are always asynchronous setTimeout(function () { handle({ onFulfilled: onFulfilled, onRejected: onRejected }); }, 0); }
這個done方法主要是把注冊的方法加入到自己這個Promise的回調(diào)列表里面。同時為了保證通過then方法注冊的function,都要在resolve之后才能調(diào)用,用了setTimeout來保證這一點(diǎn)(實現(xiàn)2是這么說的,雖然是在不同的地方用setTimeout)。
function handle(handler) { if (state === PENDING) { handlers.push(handler); } else { if (state === FULFILLED && typeof handler.onFulfilled === "function") { handler.onFulfilled(value); } if (state === REJECTED && typeof handler.onRejected === "function") { handler.onRejected(value); } } }
handle這個方法,比實現(xiàn)2的方法要簡單一點(diǎn),因為相關(guān)的邏輯在then方法里面體現(xiàn)了。
這個其實就是通過當(dāng)前的狀態(tài)來判斷是把回調(diào)加到回調(diào)列表里面還是直接執(zhí)行fulfill或者reject方法。
this.then = function (onFulfilled, onRejected) { var self = this; return new Promise(function (resolve, reject) { return self.done(function (result) { if (typeof onFulfilled === "function") { try { return resolve(onFulfilled(result)); } catch (ex) { return reject(ex); } } else { return resolve(result); } }, function (error) { if (typeof onRejected === "function") { try { return resolve(onRejected(error)); } catch (ex) { return reject(ex); } } else { return reject(error); } }); }); }
then方法很關(guān)鍵,也較難懂。這邊寫的有點(diǎn)多,感覺實現(xiàn)2寫的好一點(diǎn),把這些邏輯放在另外一個位置而不是在構(gòu)建新promise的過程中。單純從理解上來講。
首先分析下每個參數(shù)的意思。
this.then = function (onFulfilled, onRejected)這里面的onFulfilled,onRejected是then方法給當(dāng)前這個Promise注冊的兩個方法。
return new Promise(function (resolve, reject)這里的return new Promise就是為了新建一個Promise從而可以進(jìn)行鏈?zhǔn)絫hen方法的調(diào)用. then(fn1,fn2).then(fn3,fn4)=>var promise = then(fn1,fn2);
promise.then(fn3,fn4);resolve和reject則是這個新生成的promise的狀態(tài)設(shè)置方法。
self.done(function (result),function(error));調(diào)用初始的promise的done方法,將匿名函數(shù)function(result)和匿名函數(shù)function(error)添加到原始promise的回調(diào)列表。
然后再來看看匿名函數(shù)function(result)應(yīng)該怎么執(zhí)行。
function (result) { if (typeof onFulfilled === "function") { try { return resolve(onFulfilled(result)); } catch (ex) { return reject(ex); } } else { return resolve(result); } }
如果then方法注冊的是function,那么肯定是要用這個function去執(zhí)行,onFulfilled(result)就是這個作用。
resolve是新產(chǎn)生的resolve的狀態(tài)設(shè)定器。執(zhí)行完onFulfilled(result),產(chǎn)生的結(jié)果假如是newresult再交給resolve去執(zhí)行。新的promise的resolve方法就會將新的promise的狀態(tài)設(shè)置成fulfilled,那么新promise的then方法就可以在注冊完后續(xù)的方法后接著執(zhí)行。resolve(newresult)就將onFulfilled(result)產(chǎn)生的結(jié)果
傳遞給了后續(xù)的then方法注冊的function。
function getThen(value) { var t = typeof value; if (value && (t === "object" || t === "function")) { var then = value.then; if (typeof then === "function") { return then; } } return null; }
getThen方法是為了查看這個結(jié)果是不是一個Promise或者說是含有then方法的Object.如果有then方法,就把then方法返回,否則就返回null
function resolve(result) { try { var then = getThen(result); if (then) { doResolve(then.bind(result), resolve, reject) return } fulfill(result); } catch (e) { reject(e); } }
resolve這個方法可以處理參數(shù)是正常數(shù)值或者是Promise。根據(jù)Promise的使用說明,A promise resolve(Promise B),那么Promise A的狀態(tài)會在Promise B的狀態(tài)發(fā)生變化(變成fulfilled或者rejected)才會變化。首先用getThen來確定給定的參數(shù)是不是有then函數(shù)的Object,如果不是,那么就是單純的將值賦給Promise A的內(nèi)部變量value,后續(xù)回調(diào)函數(shù)就可以用這個value作為參數(shù),這也是為什么resolve能把其參數(shù)傳給通過then注冊的回調(diào)函數(shù)。那么如果是有then函數(shù)的object呢,首先getThen返回了那個object的then函數(shù)。
然后then.bind(result)是讓then函數(shù)的調(diào)用在擁有這個then函數(shù)的object里面執(zhí)行,也就是resolve的參數(shù)result。然后doResolve實際上也就是執(zhí)行了result這個promise的then方法。只不過注冊的兩個方法是當(dāng)前這個
promise的resolve和reject方法。
所以實際上執(zhí)行的是promiseB.then(resolve,reject);根據(jù)我們前面對then方法的分析可以知道。當(dāng)promiseB的狀態(tài)發(fā)生了改變,相關(guān)的回調(diào)函數(shù)會被執(zhí)行,上面注冊的是Promise A的resolve和reject方法作為promiseB的回調(diào)函數(shù),那么Promise A的resolve/reject函數(shù)會在promiseB的狀態(tài)改變后被執(zhí)行,那么PromiseA的狀態(tài)就發(fā)生了改變。同時PromiseB中產(chǎn)生的結(jié)果也會通過resolve這個函數(shù)傳給Promise A.
這個其實看實現(xiàn)2的handle方法以及then如何調(diào)用handle方法會更容易理解一點(diǎn)。而且作者畫了個很詳細(xì)的圖。
還忘了一點(diǎn),就是為啥then方法前面有this。后來我覺得無所謂,然后把this去掉了,結(jié)果在調(diào)用的時候沒法調(diào)用這個then函數(shù)。this.then應(yīng)該是接口吧。雖然當(dāng)時在W3Cschool上學(xué)習(xí)原型構(gòu)造的時候很認(rèn)真,但是還是忽略了習(xí)以為常的this。直到有的function有this,有的沒有,才感覺有點(diǎn)奇怪,我自己寫的時候怎么判斷要不要加this啊。
大致就是這樣。匿名函數(shù)的調(diào)用,傳入的參數(shù)以及實際使用的參數(shù),會引起很多干擾,說到底還是不太熟悉javascript的調(diào)用和特色吧。但是應(yīng)該有更好的書寫方式吧。所說的東西只是自以為是的理解,實在很難確信自己是對的。因為覺得是對的,所以就會朝那個方向去靠,有點(diǎn)像老師解答試卷的標(biāo)準(zhǔn)答案一樣,即使標(biāo)準(zhǔn)答案是錯的。網(wǎng)上還是充斥著很多不怎么準(zhǔn)確的東西的,還是按照自己的意愿、想法去測試下。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/90298.html
摘要:遺傳算法物競天擇,適者生存,遺傳算法就是借鑒生物體自然選擇和自然遺傳機(jī)制的隨機(jī)搜索算法。隨機(jī)生成的基因適應(yīng)度的最大值隨機(jī)生成,適應(yīng)度函數(shù)計算種群中所有對象的適應(yīng)度及總和,并對超出的基因進(jìn)行懲罰。 此為《算法的樂趣》讀書筆記,我用javascript(ES6)重新實現(xiàn)算法。 遺傳算法 物競天擇,適者生存,遺傳算法就是借鑒生物體自然選擇和自然遺傳機(jī)制的隨機(jī)搜索算法。算法的關(guān)鍵點(diǎn)有:基因的選...
摘要:強(qiáng)烈推薦上值得前端學(xué)習(xí)的數(shù)據(jù)結(jié)構(gòu)與算法項目,包含圖的演示過程與視頻講解。該倉庫包含了多種基于的算法與數(shù)據(jù)結(jié)構(gòu),提供進(jìn)一步閱讀的解釋和鏈接。數(shù)據(jù)結(jié)構(gòu)和算法必知必會的個代碼實現(xiàn)。 showImg(https://segmentfault.com/img/bVbvpYZ); 前言 算法為王。想學(xué)好前端,先練好內(nèi)功,內(nèi)功不行,就算招式練的再花哨,終究成不了高手;只有內(nèi)功深厚者,前端之路才會走得...
摘要:筆者寫的數(shù)據(jù)結(jié)構(gòu)與算法之美系列用的語言是,旨在入門數(shù)據(jù)結(jié)構(gòu)與算法和方便以后復(fù)習(xí)。這應(yīng)該是目前較為簡單的十大經(jīng)典排序算法的文章講解了吧。比如原本在的前面,而,排序之后,在的后面十大經(jīng)典排序算法冒泡排序思想冒泡排序只會操作相鄰的兩個數(shù)據(jù)。 showImg(https://segmentfault.com/img/bVbvHet); 1. 前言 算法為王。想學(xué)好前端,先練好內(nèi)功,內(nèi)功不行,就...
摘要:回顧選擇排序,插入排序,冒泡排序,快速排序,希爾排序,歸并排序,堆排序以及如何計算時間復(fù)雜度學(xué)習(xí)文章同學(xué)的描述數(shù)據(jù)結(jié)構(gòu)等同學(xué)的十大經(jīng)典算法本文代碼也上傳到了排序算法回顧。但希爾排序是非穩(wěn)定排序算法。 回顧選擇排序,插入排序,冒泡排序,快速排序,希爾排序,歸并排序,堆排序以及如何計算時間復(fù)雜度學(xué)習(xí)文章:hahda同學(xué)的javascript描述數(shù)據(jù)結(jié)構(gòu)、hustcc等同學(xué)的十大經(jīng)典算法 ...
摘要:之所以把計數(shù)排序桶排序基數(shù)排序放在一起比較,是因為它們的平均時間復(fù)雜度都為。動畫計數(shù)排序思想找出待排序的數(shù)組中最大和最小的元素。桶排序計數(shù)排序能派上用場嗎手機(jī)號碼有位,范圍太大,顯然不適合用這兩種排序算法。 showImg(https://segmentfault.com/img/bVbuF9e?w=900&h=500); 1. 前言 算法為王。 想學(xué)好前端,先練好內(nèi)功,只有內(nèi)功深厚者...
摘要:之所以把冒泡排序選擇排序插入排序放在一起比較,是因為它們的平均時間復(fù)雜度都為。其中,冒泡排序就是原地排序算法。所以冒泡排序是穩(wěn)定的排序算法。選擇排序思路選擇排序算法的實現(xiàn)思路有點(diǎn)類似插入排序,也分已排序區(qū)間和未排序區(qū)間。 showImg(https://segmentfault.com/img/bVbuvnj?w=900&h=250); 1. 前言 算法為王。 想學(xué)好前端,先練好內(nèi)功,...
閱讀 1019·2021-09-29 09:35
閱讀 1326·2021-09-28 09:36
閱讀 1613·2021-09-24 10:38
閱讀 1157·2021-09-10 11:18
閱讀 704·2019-08-30 15:54
閱讀 2577·2019-08-30 13:22
閱讀 2029·2019-08-30 11:14
閱讀 778·2019-08-29 12:35