摘要:由于引擎同一時(shí)間只執(zhí)行一段代碼這是由單線(xiàn)程的性質(zhì)決定的,所以每個(gè)代碼塊阻塞了其它異步事件的進(jìn)行。這意味著瀏覽器將等待著一個(gè)新的異步事件發(fā)生。異步的任務(wù)執(zhí)行的順序是不固定的,主要看返回的速度。
我們經(jīng)常說(shuō)JS是單線(xiàn)程的,比如node.js研討會(huì)上大家都說(shuō)JS的特色之一是單線(xiàn)程的,這樣使JS更簡(jiǎn)單明了,可是大家真的理解所謂JS的單線(xiàn)程機(jī)制嗎?單線(xiàn)程時(shí),基于事件的異步機(jī)制又該當(dāng)如何,這些知識(shí)在《JavaScript權(quán)威指南》并沒(méi)有介紹,我也一直困惑了,直到看到一篇外文,才有了些眉目,這里與大家分享下。后來(lái)發(fā)現(xiàn)《JavaScript高級(jí)程序設(shè)計(jì)》高級(jí)定時(shí)器和循環(huán)定時(shí)器介紹過(guò),不過(guò)覺(jué)得沒(méi)我翻譯這篇原文介紹得更透徹,覺(jué)得我寫(xiě)的不好的,可以查看原外文。
1 先看下兩個(gè)例子 1.1. 簡(jiǎn)單的settimeoutsetTimeout(function () { while (true) { } }, 1000); setTimeout(function () { alert("end 2"); }, 2000); setTimeout(function () { alert("end 1"); }, 100); alert("end");
執(zhí)行的結(jié)果是彈出’end’、’end 1’,然后瀏覽器假死,就是不彈出‘end 2’。也就是說(shuō)第一個(gè)settimeout里執(zhí)行的時(shí)候是一個(gè)死循環(huán),這個(gè)直接導(dǎo)致了理論上比它晚一秒執(zhí)行的第二個(gè)settimeout里的函數(shù)被阻塞,這個(gè)和我們平時(shí)所理解的異步函數(shù)多線(xiàn)程互不干擾是不符的。
附計(jì)時(shí)器使用方法
// 初始化一個(gè)簡(jiǎn)單的js的計(jì)時(shí)器,一段時(shí)間后,才觸發(fā)并執(zhí)行回調(diào)函數(shù)。 setTimeout 返回一個(gè)唯一id,可用這個(gè)id來(lái)取消這個(gè)計(jì)時(shí)器。 var id = setTimeout(fn,delay); // 類(lèi)似于setTimeout,不一樣的是,每隔一段時(shí)間,會(huì)持續(xù)調(diào)用回調(diào)fn,直到被取消 var id = setInterval(fn,delay); // 傳入一個(gè)計(jì)時(shí)器的id,取消計(jì)時(shí)器。 clearInterval(id); clearTimeout(id);1.2 ajax請(qǐng)求回調(diào)
接著我們來(lái)測(cè)試一下通過(guò)xmlhttprequest實(shí)現(xiàn)ajax異步請(qǐng)求調(diào)用,主要代碼如下:
var xmlReq = createXMLHTTP();//創(chuàng)建一個(gè)xmlhttprequest對(duì)象 function testAsynRequest() { var url = "/AsyncHandler.ashx?action=ajax"; xmlReq.open("post", url, true); xmlReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xmlReq.onreadystatechange = function () { if (xmlReq.readyState == 4) { if (xmlReq.status == 200) { var jsonData = eval("(" + xmlReq.responseText + ")"); alert(jsonData.message); } else if (xmlReq.status == 404) { alert("Requested URL is not found."); } else if (xmlReq.status == 403) { alert("Access denied."); } else { alert("status is " + xmlReq.status); } } }; xmlReq.send(null); } testAsynRequest();//1秒后調(diào)用回調(diào)函數(shù) while (true) { }
在服務(wù)端實(shí)現(xiàn)簡(jiǎn)單的輸出:
private void ProcessAjaxRequest(HttpContext context) { string action = context.Request["ajax"]; Thread.Sleep(1000);//等1秒 string jsonObject = "{"message":"" + action + ""}"; context.Response.Write(jsonObject); }
理論上,如果ajax異步請(qǐng)求,它的異步回調(diào)函數(shù)是在多帶帶一個(gè)線(xiàn)程中,那么回調(diào)函數(shù)必然不被其他線(xiàn)程”阻撓“而順利執(zhí)行,也就是1秒后,它回調(diào)執(zhí)行彈出‘a(chǎn)jax’,可是實(shí)際情況并非如此,回調(diào)函數(shù)無(wú)法執(zhí)行,因?yàn)闉g覽器再次因?yàn)樗姥h(huán)假死。
據(jù)上面兩個(gè)例子,總結(jié)如下:
JavaScript引擎是單線(xiàn)程運(yùn)行的,瀏覽器無(wú)論在什么時(shí)候都只且只有一個(gè)線(xiàn)程在運(yùn)行JavaScript程序.
JavaScript引擎用單線(xiàn)程運(yùn)行也是有意義的,單線(xiàn)程不必理會(huì)線(xiàn)程同步這些復(fù)雜的問(wèn)題,問(wèn)題得到簡(jiǎn)化。
2. JavaScript引擎可JS內(nèi)部究竟如何實(shí)現(xiàn),我們?cè)诮酉聛?lái)探討。
在了解計(jì)時(shí)器內(nèi)部運(yùn)作前,我們必須清楚一點(diǎn),觸發(fā)和執(zhí)行并不是同一概念,計(jì)時(shí)器的回調(diào)函數(shù)一定會(huì)在指定delay的時(shí)間后被觸發(fā),但并不一定立即執(zhí)行,可能需要等待。所有JavaScript代碼是在一個(gè)線(xiàn)程里執(zhí)行的,像鼠標(biāo)點(diǎn)擊和計(jì)時(shí)器之類(lèi)的事件只有在JS單線(xiàn)程空閑時(shí)才執(zhí)行。
我們來(lái)看一下圖表,一開(kāi)始你可能并沒(méi)發(fā)現(xiàn)什么或啥都不懂,但請(qǐng)靜下心來(lái),在腦海里繪制出這個(gè)場(chǎng)景
這個(gè)圖表中有許多數(shù)據(jù)信息等著我們?nèi)ダ斫?,?dāng)你完全理解了這個(gè)圖,你會(huì)對(duì)js的異步運(yùn)行機(jī)制(即JavaScript引擎如何實(shí)現(xiàn)異步事件)有很好的了解。這個(gè)圖是一維的,垂直線(xiàn)上是以毫秒計(jì)位,藍(lán)色塊代表被劃分的不同的js區(qū)域執(zhí)行代碼。例如,第一個(gè)JS區(qū)塊執(zhí)行了18毫秒,鼠標(biāo)點(diǎn)擊事件被阻塞了將近11毫秒,等等。
由于JavaScript引擎同一時(shí)間只執(zhí)行一段代碼(這是由JavaScript單線(xiàn)程的性質(zhì)決定的),所以每個(gè)JS代碼塊阻塞了其它異步事件的進(jìn)行。這意味著當(dāng)一個(gè)異步事件(像鼠標(biāo)點(diǎn)擊、計(jì)時(shí)器、Ajax)發(fā)生時(shí),這些事件的回調(diào)函數(shù)將排在隊(duì)列后面等待執(zhí)行(如何排隊(duì)完全取決于各瀏覽器,而我們可以忽視它們內(nèi)部差異,作一個(gè)簡(jiǎn)化處理)。
我們首先從第一個(gè)JS代碼塊開(kāi)始,有兩個(gè)計(jì)時(shí)器被初始化:一個(gè)10ms的setTimeout和一個(gè)10ms的setInterval觀察計(jì)時(shí)器初始化位置,(計(jì)時(shí)器初始化完畢后就會(huì)開(kāi)始計(jì)時(shí)),發(fā)現(xiàn)setTimeout計(jì)時(shí)器的回調(diào)實(shí)際上會(huì)在第一個(gè)代碼塊執(zhí)行完畢前被觸發(fā)。但是這里注意的是,它不會(huì)立即執(zhí)行(單線(xiàn)程不能這樣做)。實(shí)際上,觸發(fā)的回調(diào)將被排成一個(gè)隊(duì)列,等待下一個(gè)可執(zhí)行時(shí)間。
此外,在第一個(gè)JS代碼塊,我們發(fā)現(xiàn)一個(gè)鼠標(biāo)點(diǎn)擊事件被觸發(fā)。這個(gè)鼠標(biāo)點(diǎn)擊JS回調(diào)被綁定在異步隊(duì)列上(我們從來(lái)不知道用戶(hù)什么時(shí)候執(zhí)行這個(gè)操作,所以它被認(rèn)為是異步的)且不能馬上執(zhí)行。像初始化的計(jì)時(shí)器一樣,排隊(duì)等待執(zhí)行。
執(zhí)行完初始化JS代碼塊后,瀏覽器就有個(gè)疑問(wèn):誰(shuí)在等待執(zhí)行?此時(shí),鼠標(biāo)點(diǎn)擊回調(diào)和setTimeout計(jì)時(shí)器的回調(diào)都在等待。瀏覽器將選一個(gè)(實(shí)際上選擇了“鼠標(biāo)點(diǎn)擊事件的處理函數(shù)”,因?yàn)橛蓤D可知它是先進(jìn)隊(duì)的)并立馬執(zhí)行。而計(jì)時(shí)器的回調(diào)將等待下一合適時(shí)機(jī)執(zhí)行。
注意,鼠標(biāo)點(diǎn)擊事件執(zhí)行過(guò)程中,interval的回調(diào)第一次被觸發(fā),與setTimeout的回調(diào)一樣,排隊(duì)等待執(zhí)行。隨著時(shí)間推移,等到setTimeout計(jì)時(shí)器的回調(diào)執(zhí)行時(shí)候,setInterval的回調(diào)再次被觸發(fā),這次被觸發(fā)的回調(diào)將被拋棄(因?yàn)橐呀?jīng)有個(gè)同樣的回調(diào)在排隊(duì)了)。如果一大段代碼塊正在執(zhí)行,所有的setInterval的回調(diào)都將要排隊(duì),一旦大段代碼塊執(zhí)行完畢,這些一連串的setInterval的回調(diào)相互間將被無(wú)延遲地執(zhí)行。實(shí)際上,瀏覽器處理setInterval被觸發(fā)的回調(diào)排隊(duì)等待執(zhí)行時(shí),除非隊(duì)列中setInterval回調(diào)為空,才允許新的setInterval的回調(diào)加入。
我們發(fā)現(xiàn),setInterval的第一個(gè)被觸發(fā)的回調(diào)執(zhí)行時(shí),setInterval的回調(diào)又被觸發(fā)且排到隊(duì)列。這向我們傳達(dá)一個(gè)重要的消息:setInterval不關(guān)心目前JS正在執(zhí)行的內(nèi)容,setInterval的被觸發(fā)的回調(diào)都將會(huì)無(wú)差別地排隊(duì),這意味著兩次setInterval回調(diào)函數(shù)之間的時(shí)間間隔會(huì)被犧牲掉(縮減)。
最后,當(dāng)setInterval的回調(diào)執(zhí)行兩次后,我們發(fā)現(xiàn)沒(méi)有javascript引擎要執(zhí)行東西。這意味著瀏覽器將等待著一個(gè)新的異步事件發(fā)生。我們知道,在50ms時(shí)候,setInterval的回調(diào)再次被觸發(fā),但這次并沒(méi)有東西阻塞,所以回調(diào)就立馬執(zhí)行了。
在瀏覽器中,JavaScript引擎是基于事件驅(qū)動(dòng)的,這里的事件可看作是瀏覽器派給它的各種任務(wù),這些任務(wù)可能源自當(dāng)前執(zhí)行的代碼塊,如調(diào)用setTimeout(),也可能來(lái)自瀏覽器內(nèi)核,如onload()、onclick()、onmouseover()、setTimeOut()、setInterval()、Ajax等。如果從代碼的角度來(lái)看,所謂的任務(wù)實(shí)體就是各種回調(diào)函數(shù),由于“單線(xiàn)程”的原因,這些任務(wù)會(huì)進(jìn)行排隊(duì),一個(gè)接著一個(gè)等待著被引擎處理。(這段說(shuō)法來(lái)源于PaulGuo)
注意:
一秒一次的setInterver()執(zhí)行時(shí)插入一個(gè)耗時(shí)10s的setTimeout,可以看到setInterver是繼續(xù)執(zhí)行的,而不是一下蹦出10個(gè)setInterver()的回調(diào)。
3. 瀏覽器的三個(gè)常駐線(xiàn)程瀏覽器是多線(xiàn)程的,它們?cè)趦?nèi)核制控下相互配合以保持同步。一個(gè)瀏覽器至少實(shí)現(xiàn)三個(gè)常駐線(xiàn)程:JavaScript引擎線(xiàn)程,GUI渲染線(xiàn)程,瀏覽器事件觸發(fā)線(xiàn)程(UI線(xiàn)程)。
javascript引擎是基于事件驅(qū)動(dòng)單線(xiàn)程執(zhí)行的。JS引擎一直等待著event loop中任務(wù)的到來(lái),然后加以處理(只有當(dāng)前函數(shù)執(zhí)行棧執(zhí)行完畢,才會(huì)去任務(wù)隊(duì)列中取任務(wù)執(zhí)行)。瀏覽器無(wú)論什么時(shí)候都只有一個(gè)JS線(xiàn)程在運(yùn)行JS程序。
UI渲染線(xiàn)程負(fù)責(zé)渲染瀏覽器界面,當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時(shí),該線(xiàn)程就會(huì)執(zhí)行。但是 GUI渲染線(xiàn)程與JS引擎是互斥的,當(dāng)JS引擎執(zhí)行時(shí)GUI線(xiàn)程會(huì)被掛起,JS對(duì)頁(yè)面的操作即GUI的更新也會(huì)被保存在一個(gè)隊(duì)列中,等到JS引擎空閑時(shí)才有機(jī)會(huì)被執(zhí)行。這就是JS阻塞頁(yè)面加載。
事件觸發(fā)線(xiàn)程,當(dāng)一個(gè)事件被觸發(fā)時(shí)該線(xiàn)程會(huì)把事件添加到任務(wù)隊(duì)列的隊(duì)尾,等待JS引擎的處理。這些事件可以來(lái)自JavaScript引擎當(dāng)前執(zhí)行的代碼塊調(diào)用setTimeout/ajax添加一個(gè)任務(wù),也可以來(lái)自瀏覽器其他線(xiàn)程如鼠標(biāo)點(diǎn)擊添加的任務(wù)。但由于JS的單線(xiàn)程關(guān)系,所有這些事件都得排隊(duì)等待JS引擎處理。
javascript要等主線(xiàn)程空了才會(huì)去查看子線(xiàn)程有沒(méi)有回調(diào)內(nèi)容。異步的任務(wù)執(zhí)行的順序是不固定的,主要看返回的速度。
4. JavaScript引擎線(xiàn)程和其它偵聽(tīng)線(xiàn)程瀏覽器內(nèi)核實(shí)現(xiàn)允許多個(gè)線(xiàn)程異步執(zhí)行,這些線(xiàn)程在內(nèi)核制控下相互配合以保持同步。假如某一瀏覽器內(nèi)核的實(shí)現(xiàn)至少有三個(gè)常駐線(xiàn)程: javascript引擎線(xiàn)程,界面渲染線(xiàn)程,瀏覽器事件觸發(fā)線(xiàn)程,除些以外,也有一些執(zhí)行完就終止的線(xiàn)程,如Http請(qǐng)求線(xiàn)程,這些異步線(xiàn)程都會(huì)產(chǎn)生不同的異步事件,下面通過(guò)一個(gè)圖來(lái)闡明單線(xiàn)程的JavaScript引擎與另外那些線(xiàn)程是怎樣互動(dòng)通信的.雖然每個(gè)瀏覽器內(nèi)核實(shí)現(xiàn)細(xì)節(jié)不同,但這其中的調(diào)用原理都是大同小異.
上圖中,定時(shí)器和事件都按時(shí)觸發(fā)了,這表明JavaScript引擎的線(xiàn)程和計(jì)時(shí)器觸發(fā)線(xiàn)程、事件觸發(fā)線(xiàn)程是三個(gè)多帶帶的線(xiàn)程,即使JavaScript引擎的線(xiàn)程被阻塞,其它兩個(gè)觸發(fā)線(xiàn)程都在運(yùn)行。
線(xiàn)程間通信:JavaScript引擎執(zhí)行當(dāng)前的代碼塊,其它諸如setTimeout給JS引擎添加一個(gè)任務(wù),也可來(lái)自瀏覽器內(nèi)核的其它線(xiàn)程,如界面元素鼠標(biāo)點(diǎn)擊事件,定時(shí)觸發(fā)器時(shí)間到達(dá)通知,異步請(qǐng)求狀態(tài)變更通知等.從代碼角度看來(lái)任務(wù)實(shí)體就是各種回調(diào)函數(shù),JavaScript引擎一直等待著任務(wù)隊(duì)列中任務(wù)的到來(lái).由于單線(xiàn)程關(guān)系,這些任務(wù)得進(jìn)行排隊(duì),一個(gè)接著一個(gè)被引擎處理
GUI渲染也是在引擎線(xiàn)程中執(zhí)行的(準(zhǔn)確描述見(jiàn)下),腳本中執(zhí)行對(duì)界面進(jìn)行更新操作,如添加結(jié)點(diǎn),刪除結(jié)點(diǎn)或改變結(jié)點(diǎn)的外觀等更新并不會(huì)立即體現(xiàn)出來(lái),這些操作將保存在一個(gè)隊(duì)列中,待JavaScript引擎空閑時(shí)才有機(jī)會(huì)渲染出來(lái)。來(lái)看例子(這塊內(nèi)容還有待驗(yàn)證,個(gè)人覺(jué)得當(dāng)Dom渲染時(shí),才可阻止渲染)
渲染線(xiàn)程與JavaScript引擎線(xiàn)程是互斥的,這容易理解,因?yàn)镴avaScript腳本是可操縱DOM元素,在修改這些元素屬性同時(shí)渲染界面,那么渲染線(xiàn)程前后獲得的元素?cái)?shù)據(jù)就可能不一致了.見(jiàn)深入理解JavaScript定時(shí)機(jī)制
test
這段代碼的本意是從0開(kāi)始順序顯示數(shù)字,它們將一個(gè)接一個(gè)出現(xiàn),現(xiàn)在我們來(lái)仔細(xì)研究一下代碼,while(1)創(chuàng)建了一個(gè)無(wú)休止的循環(huán),但是對(duì)于單線(xiàn)程的JavaScript引擎而言,在實(shí)際情況中就會(huì)造成瀏覽器暫停響應(yīng)并處于假死狀態(tài)。
alert()會(huì)停止JS引擎的執(zhí)行,直到按確認(rèn)鍵,在JS調(diào)試的時(shí)候,查看當(dāng)前實(shí)時(shí)頁(yè)面的內(nèi)容。
5. setTimeout和 setInterval回到文章開(kāi)頭,我們來(lái)看下setTimeout和setsetInterval的區(qū)別。
setTimeout(function(){ /* Some long block of code ... */ setTimout(arguments.callee,10); },10); setInterval(function(){ /* Some long block of code ... */ },10);
這兩個(gè)程序段第一眼看上去是一樣的,但并不是這樣。setTimeout代碼至少每隔10ms以上才執(zhí)行一次;然而setInterval固定每隔10ms將嘗試執(zhí)行,不管它的回調(diào)函數(shù)的執(zhí)行狀態(tài)。
我們來(lái)總結(jié)下:
JavaScript引擎只有一個(gè)線(xiàn)程,強(qiáng)制異步事件排隊(duì)等待執(zhí)行。
setTimeout和setInterval在異步執(zhí)行時(shí),有著根本性不同。
如果一個(gè)計(jì)時(shí)器被阻塞執(zhí)行,它將會(huì)延遲,直到下一個(gè)可執(zhí)行點(diǎn)(這可能比期望的時(shí)間更長(zhǎng))
setInterval的回調(diào)可能被不停的執(zhí)行,中間沒(méi)間隔(如果回調(diào)執(zhí)行的時(shí)間超過(guò)預(yù)定等待的值)
《JavaScript高級(jí)程序設(shè)計(jì)》中,針對(duì)setInterval說(shuō)法如下:
當(dāng)使用setInterval()時(shí),僅當(dāng)沒(méi)有該定時(shí)器的任何其他代碼實(shí)例時(shí),才將定時(shí)器代碼添加到隊(duì)列中。還要注意兩問(wèn)題:
某些間隔會(huì)被跳過(guò)(拋棄);
多個(gè)定時(shí)器的代碼執(zhí)行之間的間隔可能會(huì)比預(yù)期小。此時(shí)可采取 setTimeout和setsetInterval的區(qū)別 的例子方法。
5. Ajax異步很多同學(xué)朋友搞不清楚,既然說(shuō)JavaScript是單線(xiàn)程運(yùn)行的,那么XMLHttpRequest在連接后是否真的異步?其實(shí)請(qǐng)求確實(shí)是異步的,不過(guò)這請(qǐng)求是由瀏覽器新開(kāi)一個(gè)線(xiàn)程請(qǐng)求(參見(jiàn)上圖),當(dāng)請(qǐng)求的狀態(tài)變更時(shí),如果先前已設(shè)置回調(diào),這異步線(xiàn)程就產(chǎn)生狀態(tài)變更事件放到JavaScript引擎的處理隊(duì)列中等待處理,當(dāng)任務(wù)被處理時(shí),JavaScript引擎始終是單線(xiàn)程運(yùn)行回調(diào)函數(shù),具體點(diǎn)即還是單線(xiàn)程運(yùn)行onreadystatechange所設(shè)置的函數(shù)。
Tip:理解JavaScript引擎運(yùn)作非常重要,特別是在大量異步事件(連續(xù))發(fā)生時(shí),可以提升程序代碼的效率。
網(wǎng)上的帖子大多深淺不一,甚至有些前后矛盾,在下的文章都是學(xué)習(xí)過(guò)程中的總結(jié),如果發(fā)現(xiàn)錯(cuò)誤,歡迎留言指出~
參考:
深入理解JavaScript定時(shí)機(jī)制
原外文
翻譯參考
部分示例
其它參考1,參考2
PS:歡迎大家關(guān)注我的公眾號(hào)【前端下午茶】,一起加油吧~
另外可以加入「前端下午茶交流群」微信群,長(zhǎng)按識(shí)別下面二維碼即可加我好友,備注加群,我拉你入群~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92020.html
摘要:學(xué)習(xí)開(kāi)發(fā),無(wú)論是前端開(kāi)發(fā)還是都避免不了要接觸異步編程這個(gè)問(wèn)題就和其它大多數(shù)以多線(xiàn)程同步為主的編程語(yǔ)言不同的主要設(shè)計(jì)是單線(xiàn)程異步模型。由于異步編程可以實(shí)現(xiàn)非阻塞的調(diào)用效果,引入異步編程自然就是順理成章的事情了。 學(xué)習(xí)js開(kāi)發(fā),無(wú)論是前端開(kāi)發(fā)還是node.js,都避免不了要接觸異步編程這個(gè)問(wèn)題,就和其它大多數(shù)以多線(xiàn)程同步為主的編程語(yǔ)言不同,js的主要設(shè)計(jì)是單線(xiàn)程異步模型。正因?yàn)閖s天生的與...
摘要:在異步機(jī)制中,任務(wù)隊(duì)列就是用來(lái)維護(hù)異步任務(wù)回調(diào)函數(shù)的隊(duì)列。四對(duì)象對(duì)象是工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口。 異步 1.JavaScript單線(xiàn)程的理解 Javascript語(yǔ)言的執(zhí)行環(huán)境是單線(xiàn)程(single thread)。所謂單線(xiàn)程,就是指一次只能完成一件任務(wù)。如果有多個(gè)任務(wù),就必須排隊(duì),前面一個(gè)任務(wù)完成,再執(zhí)行后面一個(gè)任務(wù),以此類(lèi)推。 2.JavaScript單線(xiàn)...
摘要:異步本質(zhì)上應(yīng)該就是多線(xiàn)程語(yǔ)言的產(chǎn)物。如果是多線(xiàn)程的異步,假死的應(yīng)該是運(yùn)行方法的線(xiàn)程,而方法仍然會(huì)按預(yù)期打印出。當(dāng)然了,按我個(gè)人的理解,應(yīng)該說(shuō)是是的回調(diào)函數(shù)。 引子 每個(gè)故事都有由來(lái)。前兩天在看 gulp 的時(shí)候,看到了它有個(gè) promise 的玩意兒,然后的然后,這兩天就掉進(jìn)了 javascript 的異步和回調(diào)的坑里面去了。 其間搜索了 javascript promise,看到了...
摘要:圖片轉(zhuǎn)引自的演講和兩個(gè)定時(shí)器中回調(diào)的執(zhí)行邏輯便是典型的機(jī)制。異步編程關(guān)于異步編程我的理解是,在執(zhí)行環(huán)境所提供的異步機(jī)制之上,在應(yīng)用編碼層面上實(shí)現(xiàn)整體流程控制的異步風(fēng)格。 問(wèn)題背景 在一次開(kāi)發(fā)任務(wù)中,需要實(shí)現(xiàn)如下一個(gè)餅狀圖動(dòng)畫(huà),基于canvas進(jìn)行繪圖,但由于對(duì)于JS運(yùn)行環(huán)境中異步機(jī)制的不了解,所以遇到了一個(gè)棘手的問(wèn)題,始終無(wú)法解決,之后在與同事交流之后才恍然大悟。問(wèn)題的根節(jié)在于經(jīng)典的J...
摘要:今天的已經(jīng)成為一門(mén)功能全面的編程語(yǔ)言總結(jié)最初的用途是為來(lái)實(shí)現(xiàn)用戶(hù)與瀏覽器的交互二為何是單線(xiàn)程的的單線(xiàn)程,與它的用途有關(guān)。這決定了它只能是單線(xiàn)程,否則會(huì)帶來(lái)很復(fù)雜的同步問(wèn)題。 showImg(https://user-gold-cdn.xitu.io/2019/3/31/169d1c40c27a173c?w=428&h=252&f=png&s=35393); 前言 我本來(lái)是打算寫(xiě)一篇co...
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...
閱讀 3203·2021-10-14 09:42
閱讀 3572·2019-08-26 13:56
閱讀 3480·2019-08-26 11:59
閱讀 948·2019-08-23 18:00
閱讀 2213·2019-08-23 17:51
閱讀 3534·2019-08-23 17:17
閱讀 1487·2019-08-23 15:11
閱讀 5203·2019-08-23 15:05