新聞中心
理解JavaScript的單線程的理念對(duì)于JavaScript學(xué)習(xí),以及掌握其中的一些設(shè)計(jì)機(jī)制非常重要,比如回調(diào)、定時(shí)器。對(duì)于后續(xù)學(xué)習(xí)NodeJS也有很大的幫助。

[[184669]]
通過(guò)先demo,后總結(jié)的形式,使得JavaScript的單線程更易于明白。
- 1 var a = 1; //全局變量a
- 2 function test(){
- 3 var a=2; //test中變量a
- 4 setTimeout(function(){
- 5 alert(a); //輸出test中變量a
- 6 a=3; //修改test中變量a
- 7 },3000);
- 8 a=4; //修改test中變量a
- 9 setTimeout(function(){
- 10 alert(a); //輸出test中變量a
- 11 a=5; //修改test中變量a
- 12 },1000);
- 13 alert(a); //輸出test中變量a
- 14 }
- 15 test(); //執(zhí)行test函數(shù)
- 16 alert(a); //輸出全局變量a
- //運(yùn)行結(jié)果:4 1 4 5
- /* 結(jié)果解析:先輸出test()運(yùn)行結(jié)果4,然后輸出之后一行代碼的1,然后1000ms之后輸出test()中的變量a=4,***3000ms之后輸出test()中的變量a=5 */
- /*
- 運(yùn)行機(jī)制:
- 1. JavaScript是單線程,從上往下依次執(zhí)行
- 2. setTimeout異步方法存放在任務(wù)隊(duì)列中,JS主線程執(zhí)行完成之后,才會(huì)取任務(wù)隊(duì)列中的任務(wù)到JS主線程中執(zhí)行!
- -> 先執(zhí)行15行,然后執(zhí)行16行
- -> 執(zhí)行15行,調(diào)用test()方法
- -> 調(diào)用test()方法,先創(chuàng)建一個(gè)a變量,然后將***個(gè)setTimeout放到setTimeout對(duì)應(yīng)的線程中執(zhí)行(啟動(dòng)定時(shí)器timer),第8行,修改test中變量a為4,然后將第二個(gè)setTimeout添加到setTimeout對(duì)應(yīng)的線程隊(duì)列中執(zhí)行,執(zhí)行13行,輸出test中變量a,此時(shí)為4;然后執(zhí)行16行,輸出全局變量a,此時(shí)為1.
- -> 1000ms之后,將第二個(gè)setTimeout的回調(diào)函數(shù),添加到JS任務(wù)隊(duì)列中,3000ms后將***個(gè)setTimeout的回調(diào)函數(shù),添加到JS任務(wù)隊(duì)列中。
- -> JS主線程執(zhí)行完成之后,會(huì)執(zhí)行任務(wù)隊(duì)列的事件,第二個(gè)setTimeout優(yōu)先進(jìn)入任務(wù)隊(duì)列,所以優(yōu)先執(zhí)行,執(zhí)行第10行,輸出test中的變量a,值為4,然后di11行,將test中的變量a修改為5;2000ms之后***個(gè)setTimeout進(jìn)入任務(wù)隊(duì)列,此時(shí)JS主線程棧為空,所以將其添加到JS主線程進(jìn)行執(zhí)行,第5行,輸出test中的變量a,此時(shí)變量的值為5,第6行修改test變量a為3.
- */
由此延伸以下代碼:
- var a = 1;
- var date = +new Date(); // 小技巧:通過(guò)"+"轉(zhuǎn)換為整數(shù)
- function test(){
- var a=2;
- setTimeout(function(){
- console.log(a+'--'+ (new Date()-date));
- a=3;
- },3000);
- a=4;
- setTimeout(function(){
- console.log(a+'--'+ (new Date()-date));
- a=5;
- },1000);
- console.log(a+'--'+ (new Date()-date));
- }
- while(new Date-date <1000){
- }
- test();
- console.log(a+'--'+ (new Date()-date));
- //執(zhí)行結(jié)果:4-1000 1-1001 4-2000 5-4001
結(jié)合以下博客,整理一些重要概念:
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
http://www.cnblogs.com/Mainz/p/3552717.html
1、作為腳本語(yǔ)言,JavaScript主要功能是與用戶互動(dòng),以及操作DOM。假定JavaScript同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)DOM節(jié)點(diǎn)上添加內(nèi)容,另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器應(yīng)該以哪個(gè)線程為準(zhǔn)? ->So: JavaScript就是單線程。
2、JavaScript的任務(wù)分成兩種:同步任務(wù)和異步任務(wù)。同步任務(wù):在主線程上排隊(duì)執(zhí)行的任務(wù),只有上一個(gè)任務(wù)執(zhí)行完成了,才會(huì)執(zhí)行下一個(gè)任務(wù)。異步任務(wù):不進(jìn)入主線程,而進(jìn)入“任務(wù)隊(duì)列”的任務(wù),只有“任務(wù)隊(duì)列”通知主線程,某個(gè)任務(wù)隊(duì)列可以執(zhí)行了,等主線程執(zhí)行完成,任務(wù)隊(duì)列才會(huì)進(jìn)入主線程執(zhí)行。 -> So:只要主線程空了,就會(huì)去讀“任務(wù)隊(duì)列”,這就是JavaScript的運(yùn)行機(jī)制。
3、主線程從“任務(wù)隊(duì)列”中讀取事件,這個(gè)過(guò)程是循環(huán)不斷的,所以整個(gè)事件又叫“事件循環(huán)”(Event Loop)。
HTML5規(guī)定setTimeout()的第二個(gè)參數(shù)的最小值(最短間隔),不得低于4ms,如果低于4ms就會(huì)自動(dòng)增加。在此之前,老版本瀏覽的都將最短時(shí)間設(shè)置為10ms。另外,對(duì)于那些DOM變動(dòng)(尤其是設(shè)計(jì)頁(yè)面重新渲染的部分),通常不會(huì)立即執(zhí)行,而是每16ms執(zhí)行一次。這是使用requestAnimationFrame()的效果要好于setTimeout()。
4、需要注意的是:setTimeout只是將事件插入“事件隊(duì)列”,必須等到前面代碼(執(zhí)行棧)執(zhí)行完,主線程才會(huì)去執(zhí)行他指定的回調(diào)函數(shù)。如果當(dāng)前代碼耗時(shí)很長(zhǎng),有可能要等很久,所以并沒(méi)有辦法保證,回調(diào)函數(shù)一定會(huì)在setTimeout()指定的是時(shí)間執(zhí)行。
Javascript是單線程,單線程就意味著所有任務(wù)需要排隊(duì)。然后會(huì)將所有任務(wù)分成兩類:同步任務(wù)和異步任務(wù)!同步任務(wù):在主線程上執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完成,才會(huì)執(zhí)行后一個(gè)!異步任務(wù):不進(jìn)入主線程、而進(jìn)入“任務(wù)隊(duì)列”的任務(wù)。
Js是單線程的,但是瀏覽器是多線程的!瀏覽器是事件驅(qū)動(dòng)的!
JS運(yùn)行在瀏覽器中,是單線程的,每個(gè)window一個(gè)JS線程,但是瀏覽器不是單線程??赡苡卸鄠€(gè)如下線程:
Javascript引擎線程、界面渲染線程、瀏覽器事件觸發(fā)線程、Http請(qǐng)求線程。
setTimeout可以改變,js執(zhí)行順序。比如:我們想要輸出Hello World,world必須在hello之后輸出,不管我們代碼的順序怎么樣都輸出同樣的效果,這個(gè)時(shí)候就可以借助setTimeout。
- //代碼一
- var date = +new Date();
- console.log('Hello',new Date()-date);
- setTimeout(function(){
- console.log('world',new Date()-date);
- },500);
- //代碼二:
- var date = +new Date();
- setTimeout(function(){
- console.log('World',new Date()-date);
- },500);
- console.log('Hello',new Date()-date);
- //以上兩個(gè)代碼運(yùn)行結(jié)果一樣,結(jié)果都是:先輸出Hello ,然后500ms之后輸出World![實(shí)際運(yùn)行:501ms]
瀏覽器中定時(shí)器也是一個(gè)線程!
Javscript是單線程的,ajax請(qǐng)求確實(shí)是異步的!原因是ajax請(qǐng)求的時(shí)候,是在瀏覽器的Http請(qǐng)求線程中執(zhí)行的,執(zhí)行之后的回調(diào)函數(shù)會(huì)放到Javascript線程中執(zhí)行!
Summary:
Javascript是單線程的,瀏覽器是多線程的,瀏覽器的線程包括:JS引擎線程、界面渲染線程、瀏覽器事件線程、Http請(qǐng)求線程。不過(guò)不同的瀏覽器提供的線程是有區(qū)別的。一般JS引擎線程和界面渲染線程是互斥的,兩個(gè)線程不能同時(shí)執(zhí)行,否則,就會(huì)出現(xiàn)界面渲染線程和JS線程修改同一個(gè)DOM樣式的矛盾問(wèn)題!
當(dāng)前名稱:JavaScript單線程&setTimeout定時(shí)器
鏈接地址:http://www.fisionsoft.com.cn/article/dhdsheg.html


咨詢
建站咨詢
