同步任務(wù) && 異步任務(wù)
程序里面所有的任務(wù),可以分成兩類:同步任務(wù)(synchronous)和異步任務(wù)(asynchronous)昔期。
同步任務(wù)是那些沒有被引擎掛起、在主線程上排隊(duì)執(zhí)行的任務(wù)。只有前一個(gè)任務(wù)執(zhí)行完畢晚顷,才能執(zhí)行后一個(gè)任務(wù)。
異步任務(wù)是那些被引擎放在一邊疗疟,不進(jìn)入主線程该默、而進(jìn)入任務(wù)隊(duì)列的任務(wù)。只有引擎認(rèn)為某個(gè)異步任務(wù)可以執(zhí)行了(比如 Ajax 操作從服務(wù)器得到了結(jié)果)策彤,該任務(wù)(采用回調(diào)函數(shù)的形式)才會(huì)進(jìn)入主線程執(zhí)行栓袖。排在異步任務(wù)后面的代碼匣摘,不用等待異步任務(wù)結(jié)束會(huì)馬上運(yùn)行,也就是說裹刮,異步任務(wù)不具有”堵塞“效應(yīng)音榜。
舉例來說,Ajax 操作可以當(dāng)作同步任務(wù)處理捧弃,也可以當(dāng)作異步任務(wù)處理赠叼,由開發(fā)者決定。如果是同步任務(wù)违霞,主線程就等著 Ajax 操作返回結(jié)果嘴办,再往下執(zhí)行;如果是異步任務(wù)买鸽,主線程在發(fā)出 Ajax 請(qǐng)求以后涧郊,就直接往下執(zhí)行,等到 Ajax 操作有了結(jié)果眼五,主線程再執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)妆艘。
任務(wù)隊(duì)列和事件循環(huán)
JavaScript 運(yùn)行時(shí),除了一個(gè)正在運(yùn)行的主線程看幼,引擎還提供一個(gè)任務(wù)隊(duì)列(task queue)批旺,里面是各種需要當(dāng)前程序處理的異步任務(wù)。
首先桌吃,主線程會(huì)去執(zhí)行所有的同步任務(wù)朱沃,等到同步任務(wù)執(zhí)行完了,就去看任務(wù)隊(duì)列里面的異步任務(wù)茅诱。如果滿足條件逗物,那么異步任務(wù)就會(huì)進(jìn)入主線
程開始執(zhí)行,這時(shí)他就變成同步任務(wù)了瑟俭。等到執(zhí)行完翎卓,下一個(gè)異步任務(wù)再進(jìn)入主線程開始執(zhí)行。一旦任務(wù)隊(duì)列清空摆寄,程序就結(jié)束執(zhí)行失暴。
異步任務(wù)通常寫法是回調(diào)函數(shù),一旦異步任務(wù)進(jìn)入主線程微饥,就會(huì)執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)逗扒,如果異步任務(wù)沒有回調(diào)函數(shù),那么就不會(huì)進(jìn)入任務(wù)隊(duì)列欠橘,
也就是說不會(huì)重新進(jìn)入主線程矩肩。那么問題來了,JS引擎是如何知道異步任務(wù)有沒有結(jié)果肃续,能不能進(jìn)入主線程呢黍檩?答案是JS引擎在不斷地檢查叉袍,一遍又一遍,只要同步任務(wù)執(zhí)行完了刽酱,引擎就會(huì)去檢查那些掛起來的異步任務(wù)喳逛,是不是可以進(jìn)入主線程。這種循環(huán)檢查的機(jī)制棵里,就是事件循環(huán)(Event Loop)润文。