javascript從誕生之日起就是一門單線程的非阻塞的腳本語言
單線程意味著规婆,javascript代碼在執(zhí)行的任何時(shí)候赊堪,都只有一個(gè)主線程來處理所有的任務(wù)。
而非阻塞則是當(dāng)代碼需要進(jìn)行一項(xiàng)異步任務(wù)(無法立刻返回結(jié)果捐康,需要花一定時(shí)間才能返回的任務(wù)畦幢,如I/O事件)的時(shí)候,主線程會掛起(pending)這個(gè)任務(wù)潮孽,然后在異步任務(wù)返回結(jié)果的時(shí)候再根據(jù)一定規(guī)則去執(zhí)行相應(yīng)的回調(diào)揪荣。
執(zhí)行棧與事件隊(duì)列
當(dāng)javascript代碼執(zhí)行的時(shí)候會將不同的變量存于內(nèi)存中的不同位置:堆(heap)和棧(stack)中來加以區(qū)分。其中恩商,堆里存放著一些對象变逃。而棧中則存放著一些基礎(chǔ)類型變量以及對象的指針。
當(dāng)我們調(diào)用一個(gè)方法的時(shí)候怠堪,js會生成一個(gè)與這個(gè)方法對應(yīng)的執(zhí)行環(huán)境(context)揽乱,又叫執(zhí)行上下文。這個(gè)執(zhí)行環(huán)境中存在著這個(gè)方法的私有作用域粟矿,上層作用域的指向凰棉,方法的參數(shù),這個(gè)作用域中定義的變量以及這個(gè)作用域的this對象陌粹。 而當(dāng)一系列方法被依次調(diào)用的時(shí)候撒犀,因?yàn)閖s是單線程的,同一時(shí)間只能執(zhí)行一個(gè)方法掏秩,于是這些方法被排隊(duì)在一個(gè)單獨(dú)的地方或舞。這個(gè)地方被稱為執(zhí)行棧。
js引擎遇到一個(gè)異步事件后并不會一直等待其返回結(jié)果蒙幻,而是會將這個(gè)事件掛起映凳,繼續(xù)執(zhí)行執(zhí)行棧中的其他任務(wù)。當(dāng)一個(gè)異步事件返回結(jié)果后邮破,js會將這個(gè)事件加入事件隊(duì)列诈豌。被放入事件隊(duì)列不會立刻執(zhí)行其回調(diào)仆救,而是等待當(dāng)前執(zhí)行棧中的所有任務(wù)都執(zhí)行完畢, 主線程處于閑置狀態(tài)時(shí)矫渔,主線程會去查找事件隊(duì)列是否有任務(wù)彤蔽。如果有,那么主線程會從中取出排在第一位的事件庙洼,并把這個(gè)事件對應(yīng)的回調(diào)放入執(zhí)行棧中顿痪,然后執(zhí)行其中的同步代碼...,如此反復(fù)送膳,這樣就形成了一個(gè)無限的循環(huán)员魏。這就是這個(gè)過程被稱為“事件循環(huán)(Event Loop)”的原因。