最基礎(chǔ)的異步是setTimeout和setInterval函數(shù)
很常見(jiàn)斋扰,但是很少人有人知道其實(shí)這就是異步,因?yàn)樗鼈兛梢钥刂苆s的執(zhí)行順序券盅。我們也可以簡(jiǎn)單地理解為:可以改變程序正常執(zhí)行順序的操作就可以看成是異步操作景描。如下代碼:
<script type="text/javascript">
console.log( "1" );
setTimeout(function() {
console.log( "2" )
}, 0 );
setTimeout(function() {
console.log( "3" )
}, 0 );
setTimeout(function() {
console.log( "4" )
}, 0 );
console.log( "5" );
</script>
輸出順序是什么呢?
15234
來(lái)自群管大大的解釋:setTimeout(function() {
console.log( "2" )
}, 0 );
換了個(gè)堆棧了偏化,異步函數(shù)都會(huì)換下一個(gè)堆棧,
a方法調(diào)用b方法, 一連串的方法調(diào)用 是一個(gè)堆棧
一旦出現(xiàn)異步函數(shù), 回調(diào)方法里面, 就會(huì)放到下一個(gè)堆棧
等這個(gè)堆棧執(zhí)行完畢, 再等回調(diào)事件出現(xiàn), 才執(zhí)行剛才放下的下一個(gè)堆棧
可見(jiàn),盡管我們?cè)O(shè)置了setTimeout(function镐侯,time)中的等待時(shí)間為0侦讨,結(jié)果其中的function還是后執(zhí)行。
見(jiàn)苟翻,盡管我們?cè)O(shè)置了setTimeout(function韵卤,time)中的等待時(shí)間為0,結(jié)果其中的function還是后執(zhí)行崇猫。
火狐瀏覽器的api文檔有這樣一句話:Because even though setTimeout was called with a delay of zero, it's placed on a queue and scheduled to run at the next opportunity, not immediately. Currently executing code must complete before functions on the queue are executed, the resulting execution order may not be as expected.
意思就是:盡管setTimeout的time延遲時(shí)間為0沈条,其中的function也會(huì)被放入一個(gè)隊(duì)列中,等待下一個(gè)機(jī)會(huì)執(zhí)行诅炉,當(dāng)前的代碼(指不需要加入隊(duì)列中的程序)必須在該隊(duì)列的程序完成之前完成蜡歹,因此結(jié)果可能不與預(yù)期結(jié)果相同。
這里說(shuō)到了一個(gè)“隊(duì)列”(即任務(wù)隊(duì)列)汞扎,該隊(duì)列放的是什么呢季稳,放的就是setTimeout中的function擅这,這些function依次加入該隊(duì)列澈魄,即該隊(duì)列中所有function中的程序?qū)?huì)在該隊(duì)列以外的所有代碼執(zhí)行完畢之后再以此執(zhí)行,這是為什么呢仲翎?因?yàn)樵趫?zhí)行程序的時(shí)候痹扇,瀏覽器會(huì)默認(rèn)setTimeout以及ajax請(qǐng)求這一類的方法都是耗時(shí)程序(盡管可能不耗時(shí)),將其加入一個(gè)隊(duì)列中溯香,該隊(duì)列是一個(gè)存儲(chǔ)耗時(shí)程序的隊(duì)列鲫构,在所有不耗時(shí)程序執(zhí)行過(guò)后,再來(lái)依次執(zhí)行該隊(duì)列中的程序玫坛。
又回到了最初的起點(diǎn)——javascript是單線程结笨。
單線程就意味著,所有任務(wù)需要排隊(duì),前一個(gè)任務(wù)結(jié)束炕吸,才會(huì)執(zhí)行后一個(gè)任務(wù)伐憾。如果前一個(gè)任務(wù)耗時(shí)很長(zhǎng),后一個(gè)任務(wù)就不得不一直等著赫模。于是就有一個(gè)概念——任務(wù)隊(duì)列树肃。
如果排隊(duì)是因?yàn)橛?jì)算量大,CPU忙不過(guò)來(lái)瀑罗,倒也算了胸嘴,但是很多時(shí)候CPU是閑著的,因?yàn)镮O設(shè)備(輸入輸出設(shè)備)很慢(比如Ajax操作從網(wǎng)絡(luò)讀取數(shù)據(jù))斩祭,不得不等著結(jié)果出來(lái)劣像,再往下執(zhí)行。于是JavaScript語(yǔ)言的設(shè)計(jì)者意識(shí)到摧玫,這時(shí)主線程完全可以不管IO設(shè)備驾讲,掛起處于等待中的任務(wù),先運(yùn)行排在后面的任務(wù)席赂。等到IO設(shè)備返回了結(jié)果吮铭,再回過(guò)頭,把掛起的任務(wù)繼續(xù)執(zhí)行下去颅停。
于是谓晌,所有任務(wù)可以分成兩種,一種是同步任務(wù)(synchronous)癞揉,另一種是異步任務(wù)(asynchronous)纸肉。同步任務(wù)指的是,在主線程上排隊(duì)執(zhí)行的任務(wù)喊熟,只有前一個(gè)任務(wù)執(zhí)行完畢柏肪,才能執(zhí)行后一個(gè)任務(wù);異步任務(wù)指的是芥牌,不進(jìn)入主線程烦味、而進(jìn)入"任務(wù)隊(duì)列"(task queue)的任務(wù),只有等主線程任務(wù)執(zhí)行完畢壁拉,"任務(wù)隊(duì)列"開(kāi)始通知主線程谬俄,請(qǐng)求執(zhí)行任務(wù),該任務(wù)才會(huì)進(jìn)入主線程執(zhí)行弃理。
具體來(lái)說(shuō)溃论,異步運(yùn)行機(jī)制如下:
(1)所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)痘昌。
(2)主線程之外钥勋,還存在一個(gè)"任務(wù)隊(duì)列"(task queue)炬转。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件算灸。
(3)一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢返吻,系統(tǒng)就會(huì)讀取"任務(wù)隊(duì)列",看看里面有哪些事件乎婿。那些對(duì)應(yīng)的異步任務(wù)测僵,于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧谢翎,開(kāi)始執(zhí)行捍靠。
(4)主線程不斷重復(fù)上面的第三步。
只要主線程空了森逮,就會(huì)去讀取"任務(wù)隊(duì)列"榨婆,這就是JavaScript的運(yùn)行機(jī)制。這個(gè)過(guò)程會(huì)不斷重復(fù)褒侧。
"任務(wù)隊(duì)列"是一個(gè)事件的隊(duì)列(也可以理解成消息的隊(duì)列)良风,IO設(shè)備完成一項(xiàng)任務(wù),就在"任務(wù)隊(duì)列"中添加一個(gè)事件闷供,表示相關(guān)的異步任務(wù)可以進(jìn)入"執(zhí)行棧"了烟央。主線程讀取"任務(wù)隊(duì)列",就是讀取里面有哪些事件歪脏。
"任務(wù)隊(duì)列"中的事件疑俭,除了IO設(shè)備的事件以外,還包括一些用戶產(chǎn)生的事件(比如鼠標(biāo)點(diǎn)擊婿失、頁(yè)面滾動(dòng)等等)钞艇,比如$(selectot).click(function),這些都是相對(duì)耗時(shí)的操作豪硅。只要指定過(guò)這些事件的回調(diào)函數(shù)哩照,這些事件發(fā)生時(shí)就會(huì)進(jìn)入"任務(wù)隊(duì)列",等待主線程讀取懒浮。
所謂"回調(diào)函數(shù)"(callback)飘弧,就是那些會(huì)被主線程掛起來(lái)的代碼,前面說(shuō)的點(diǎn)擊事件$(selectot).click(function)中的function就是一個(gè)回調(diào)函數(shù)嵌溢。異步任務(wù)必須指定回調(diào)函數(shù)眯牧,當(dāng)主線程開(kāi)始執(zhí)行異步任務(wù),就是執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)赖草。例如ajax的success,complete剪个,error也都指定了各自的回調(diào)函數(shù)秧骑,這些函數(shù)就會(huì)加入“任務(wù)隊(duì)列”中,等待執(zhí)行.
李炎恢的XML筆記:
同步及異步
load()方法是用于服務(wù)器端載入XML的,并且限制在同一臺(tái)服務(wù)器上的XML文件乎折,那么在載入的時(shí)候有兩種模式:同步和異步绒疗。
所謂同步:就是在加載XML完成之前,代碼不會(huì)繼續(xù)執(zhí)行骂澄,直到完全加載了XML再返回吓蘑。好處就是簡(jiǎn)單方便 壞處就是如果加載的數(shù)據(jù)停止響應(yīng)或延遲太久,瀏覽器會(huì)一直堵塞從而造成假死狀態(tài)坟冲。
xmlDom.async = false; //設(shè)置同步磨镶,false,可以用PHP測(cè)試假死
所謂異步:就是加載XML時(shí),JavaScript會(huì)把任務(wù)丟給瀏覽器內(nèi)部后臺(tái)去處理健提,不會(huì)造成堵塞琳猫,但要配合readystatechange事件使用,所以私痹, 通常我們都使用異步方式脐嫂。
xmlDom.async= true //設(shè)置異步,默認(rèn)
通過(guò)異步加載紊遵,我們發(fā)現(xiàn)獲取不到XML的信息账千,原因是,它并沒(méi)有完全加載XML就返回了暗膜,也就是說(shuō)蕊爵,在瀏覽器內(nèi)部加載一點(diǎn),返回一點(diǎn)桦山,加載一點(diǎn)攒射,返回一點(diǎn),這個(gè)時(shí)候 恒水,我們需要判斷是否完全加載会放,并且可以使用了,再進(jìn)行獲取輸出钉凌。
var xmlDom = createXMLDOM();
xmlDom.async = true; //同步設(shè)置false 異步設(shè)置true,默認(rèn)是異步
xmlDom.onreadystatechange =function(){
if(xmlDom.readyState==4){
alert(xmlDom.xml)
}
}
xmlDom.load('demo.xml');