JavaScript作為一門(mén)編程語(yǔ)言,在前端開(kāi)發(fā)中扮演著很重要的角色。而其中一個(gè)非常特殊的特點(diǎn)就是JavaScript是單線程的。
什么是單線程?舉個(gè)例子,當(dāng)你在瀏覽器中使用JavaScript進(jìn)行操作時(shí),如果代碼中出現(xiàn)了需要等待的事件,例如Ajax請(qǐng)求,JavaScript會(huì)一直等待該請(qǐng)求返回結(jié)果后再繼續(xù)執(zhí)行下一步操作。這就意味著JavaScript代碼在執(zhí)行期間會(huì)阻塞其他代碼的執(zhí)行。這種執(zhí)行模式類似于排隊(duì)式,只要前面的任務(wù)沒(méi)有完成,后續(xù)的任務(wù)就不會(huì)被執(zhí)行。
// 簡(jiǎn)單的例子 console.log('Start') setTimeout(() =>{ console.log('1000 ms later') }, 1000) console.log('End') // Start // End // 1 秒后 // 1000 ms later
這是一個(gè)非常簡(jiǎn)單的示例,我們通過(guò)setTimeout來(lái)模擬一個(gè)需要等待一定時(shí)間才能執(zhí)行的事件。當(dāng)代碼運(yùn)行到setTimeout這一步時(shí),JavaScript會(huì)等待1秒鐘,直到定時(shí)器結(jié)束才會(huì)回調(diào)console.log('1000 ms later')。由此可見(jiàn),JavaScript是單線程的這一特點(diǎn),對(duì)于應(yīng)用的性能影響非常大。
是什么導(dǎo)致了JavaScript成為單線程的編程語(yǔ)言呢?事實(shí)上,這和JavaScript的早期設(shè)計(jì)有很大關(guān)系。在JavaScript作為一門(mén)腳本語(yǔ)言的時(shí)候,它的主要目標(biāo)是在瀏覽器中操作文檔。此時(shí),為了確保操作文檔的可靠性和一致性,JavaScript被設(shè)計(jì)成為單線程的執(zhí)行模式。
除此之外,JavaScript還具備一些其他的特點(diǎn),例如基于回調(diào)式的異步編程。在瀏覽器中,異步編程非常常見(jiàn),例如事件處理、Ajax請(qǐng)求等等。而JavaScript正好能滿足這些需要,通過(guò)回調(diào)函數(shù)的形式,來(lái)實(shí)現(xiàn)在單線程模式下也能夠處理異步請(qǐng)求的需求。
// 異步請(qǐng)求示例 console.log('Start') fetch('https://jsonplaceholder.typicode.com/todos/1') .then(res =>res.json()) .then(data =>console.log(data)) console.log('End') // Start // End // 請(qǐng)求結(jié)果 // {userId: 1, id: 1, title: "delectus aut autem", completed: false}
可以看到,在異步請(qǐng)求的示例中,fetch請(qǐng)求會(huì)被放入任務(wù)隊(duì)列中進(jìn)行異步處理,而JavaScript會(huì)繼續(xù)執(zhí)行console.log('End')。當(dāng)請(qǐng)求處理完成后,JavaScript才會(huì)回調(diào).then方法中的邏輯進(jìn)行處理。
雖然JavaScript是單線程的編程語(yǔ)言,但是在實(shí)際開(kāi)發(fā)中,我們可以通過(guò)一些方法來(lái)減小這一特點(diǎn)對(duì)性能的影響。例如通過(guò)Web Worker實(shí)現(xiàn)多線程處理、使用setTimeout和setInterval分解任務(wù)等等。
總之,雖然JavaScript是單線程的,但是在這種編程模式下,JavaScript仍然可以勝任大部分的任務(wù),而且它的回調(diào)式異步編程模式也經(jīng)過(guò)了長(zhǎng)時(shí)間的檢驗(yàn)和實(shí)踐,被證明是非??煽亢挽`活的。因此,在實(shí)際開(kāi)發(fā)中,我們不必過(guò)分擔(dān)心JavaScript是單線程的問(wèn)題,只需要根據(jù)實(shí)際需要來(lái)選擇最適合自己的編程模式即可。