一、JavaScript是單線程的
- 首先
javascript語言是一門“單線程”的語言
,不像java語言,類繼承Thread再來個(gè)thread.start就可以開辟一個(gè)線程签赃,所以谷异,javascript就像一條流水線,僅僅是一條流水線而已锦聊,要么加工歹嘹,要么包裝,不能同時(shí)進(jìn)行多個(gè)任務(wù)和流程孔庭。 - 單線程就意味著尺上,所有任務(wù)需要排隊(duì),前一個(gè)任務(wù)結(jié)束史飞,才會執(zhí)行后一個(gè)任務(wù)尖昏。如果前一個(gè)任務(wù)耗時(shí)很長,后一個(gè)任務(wù)就不得不一直等著构资。于是就有一個(gè)概念——任務(wù)隊(duì)列。如果排隊(duì)是因?yàn)橛?jì)算量大陨簇,CPU忙不過來吐绵,倒也算了,但是很多時(shí)候CPU是閑著的河绽,因?yàn)镮O設(shè)備(輸入輸出設(shè)備)很慢(比如Ajax操作從網(wǎng)絡(luò)讀取數(shù)據(jù))己单,不得不等著結(jié)果出來,再往下執(zhí)行耙饰。于是JavaScript語言的設(shè)計(jì)者意識到纹笼,這時(shí)主線程完全可以不管IO設(shè)備,掛起處于等待中的任務(wù)苟跪,先運(yùn)行排在后面的任務(wù)廷痘。等到IO設(shè)備返回了結(jié)果,再回過頭件已,把掛起的任務(wù)繼續(xù)執(zhí)行下去笋额。
JS為何是單線程的?
JavaScript的單線程篷扩,與它的用途有關(guān)兄猩。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動(dòng)鉴未,以及操作DOM枢冤。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題铜秆。
比如淹真,假定JavaScript同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)DOM節(jié)點(diǎn)上添加內(nèi)容羽峰,另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn)趟咆,這時(shí)瀏覽器應(yīng)該以哪個(gè)線程為準(zhǔn)添瓷?
所以,為了避免復(fù)雜性值纱,從一誕生鳞贷,JavaScript就是單線程,這已經(jīng)成這門語言的核心特征虐唠,將來也不會改變搀愧。
注:所謂單線程,是指在JS引擎中負(fù)責(zé)解釋和執(zhí)行JavaScript代碼的線程只有一個(gè)疆偿。
二咱筛、同步(Synchronous)和異步(Asynchronous)是什么意思?
- 于是杆故,所有任務(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ì)列"開始通知主線程讨衣,請求執(zhí)行任務(wù)换棚,該任務(wù)才會進(jìn)入主線程執(zhí)行。
- “同步”可能讓人聯(lián)想到“一起”這個(gè)詞值依;
- “異步”從字面來講圃泡,好像是在不同的(異)的ways上do something,那首先想到的詞可能是“一邊...一邊...”,比如‘小明一邊吃雪糕一邊寫作業(yè)’愿险,這完全沒毛病颇蜡,雪糕吃完了,作業(yè)也寫完了辆亏,這就是異步风秤?那就大錯(cuò)特錯(cuò)了!
同步和異步扮叨,無論如何缤弦,做事情的時(shí)候都是只有一條流水線(單線程),同步和異步的差別就在于這條流水線上各個(gè)流程的執(zhí)行順序不同彻磁。
- 在計(jì)算機(jī)領(lǐng)域碍沐,
同步
就是指一個(gè)進(jìn)程在執(zhí)行某個(gè)請求的時(shí)候狸捅,若該請求需要一段時(shí)間才能返回信息,那么這個(gè)進(jìn)程將會一直等待下去累提,直到收到返回信息才繼續(xù)執(zhí)行下去尘喝;異步
是指進(jìn)程不需要一直等下去,而是繼續(xù)執(zhí)行下面的操作斋陪,不管其他進(jìn)程的狀態(tài)朽褪。當(dāng)有消息返回時(shí)系統(tǒng)會通知進(jìn)程進(jìn)行處理,這樣可以提高執(zhí)行的效率无虚。 - 形象的說同步就是你去商城買手機(jī)缔赠,店家說你這款手機(jī)在倉庫,他就去倉庫拿貨友题,你得在店里等著嗤堰,不能離開,這叫做同步度宦。而異步就是你現(xiàn)在你在網(wǎng)上下單買手機(jī)梁棠,下單完成后你就可用做其他時(shí)間(追劇、打王者斗埂、lol)等貨到了去簽收就好了,這就叫異步凫海。
二呛凶、舉例說明
最基礎(chǔ)的異步是setTimeout
和setInterval
函數(shù),很常見行贪,但是很少人有人知道其實(shí)這就是異步漾稀,因?yàn)樗鼈兛梢钥刂苆s的執(zhí)行順序。我們也可以簡單地理解為:可以改變程序正常執(zhí)行順序的操作就可以看成是異步操作建瘫。
<script>
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>
輸出結(jié)果是 : 1 5 2 3 4
盡管我們設(shè)置了setTimeout(function崭捍,time)中的等待時(shí)間為0,結(jié)果其中的function還是后執(zhí)行啰脚。
- 盡管setTimeout的time延遲時(shí)間為0殷蛇,其中的function也會被放入一個(gè)隊(duì)列中,等待下一個(gè)機(jī)會執(zhí)行橄浓,當(dāng)前的代碼(指不需要加入隊(duì)列中的程序console.log( "1" );與console.log( "5" );)必須在該隊(duì)列的程序完成之前完成粒梦,因此結(jié)果可能不與預(yù)期結(jié)果相同。
這里說到了一個(gè)“隊(duì)列”(即任務(wù)隊(duì)列)荸实,該隊(duì)列放的是什么呢匀们,放的就是setTimeout中的function,這些function依次加入該隊(duì)列准给,即該隊(duì)列中所有function中的程序?qū)谠撽?duì)列以外的所有代碼執(zhí)行完畢之后再以此執(zhí)行泄朴,這是為什么呢重抖?因?yàn)樵趫?zhí)行程序的時(shí)候,瀏覽器會默認(rèn)setTimeout以及ajax請求這一類的方法都是耗時(shí)程序(盡管可能不耗時(shí))祖灰,將其加入一個(gè)隊(duì)列中钟沛,該隊(duì)列是一個(gè)存儲耗時(shí)程序的隊(duì)列,在所有不耗時(shí)程序執(zhí)行過后夫植,再來依次執(zhí)行該隊(duì)列中的程序讹剔。
三、在JS中異步編程只有四種情況:
- 定時(shí)器都是異步編程的
- 所有的事件都是異步編程的
- Ajax讀取數(shù)據(jù)的時(shí)候, 我們一般都設(shè)置為異步編程
- 回調(diào)函數(shù)也都是異步編程的