從settimeout看javascript的運行機制

前言

咱們知道JS是一個單線程的語言,並且其運行機制比較特殊。
下面咱們經過settimeout的幾個示例來展示javascript的運行機制的特殊點javascript

示例1

console.log(1);
setTimeout(function(){
    console.log(2);
},0);
console.log(3);
// 打印出 1 3 2

示例2

console.log('1');
setTimeout(function(){
    console.log('2');
},0);
while(1){}
// 打印出1,而後瀏覽器卡死,不會打印出2

javascript會先把須要運行的內容放到任務隊列中
可是若是遇到settimeout,會認爲這是個異步任務,會先放到異步隊列中
瀏覽器會先執行同步任務,等到同步任務執行完以後,再查看異步隊列
若是異步隊列中的任務的執行時機到了,瀏覽器就會把任務放到同步隊列中去。java

即:
異步任務必定在同步任務以後執行。瀏覽器

示例3

for(var i = 0; i < 4; i++){
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
// 打印 4 4 4 4

爲何打印出的是4 4 4 4呢?
由於瀏覽器會先執行for循環
每執行一次for循環,都把一個settimeout壓入異步隊列
1000毫秒以後,執行settimeout裏的方法的時候,i的值已是4了。緩存

若是要打印0 1 2 3怎麼辦呢?
利用閉包的特性,把i緩存到一個temp值裏閉包

for(var i = 0; i < 4; i++){
    (function(temp){
        setTimeout(function() {
            console.log(temp);
        }, 1000);
    })(i);
}
// 打印 0 1 2 3

這樣作等因而每一次for循環都新建了一個匿名函數,i的值被存入了這個匿名函數的內存裏。
理解了閉包的同窗必定能夠理解這一點。異步

示例4

咱們知道ES6引入了新的關鍵字let
在這裏,let有一個新的特性函數

for(let i = 0; i < 4; i ++){
    setTimeout(function(){
        console.log(i); 
    }, 1000);
}
// 打印 0 1 2 3

示例4與示例3只有var和let這個地方有區別,可是打印出來的結果卻徹底不一樣
這是由於let是一個塊級做用域
let定義的i,對於每個for循環的執行來講都是一個全新的i(使用不一樣的內存地址)
因此打印的時候能夠獲得0 1 2 3線程

相關文章
相關標籤/搜索