真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

從setTimeout看js函數(shù)執(zhí)行過程

老實(shí)說,寫這篇文章的時候心里是有點(diǎn)壓抑的,因?yàn)槭艿酱驌袅?為什么?就 因?yàn)橄矚g折騰不小心看到了這個"簡單"的函數(shù):

創(chuàng)新互聯(lián)自成立以來,一直致力于為企業(yè)提供從網(wǎng)站策劃、網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、電子商務(wù)、網(wǎng)站推廣、網(wǎng)站優(yōu)化到為企業(yè)提供個性化軟件開發(fā)等基于互聯(lián)網(wǎng)的全面整合營銷服務(wù)。公司擁有豐富的網(wǎng)站建設(shè)和互聯(lián)網(wǎng)應(yīng)用系統(tǒng)開發(fā)管理經(jīng)驗(yàn)、成熟的應(yīng)用系統(tǒng)解決方案、優(yōu)秀的網(wǎng)站開發(fā)工程師團(tuán)隊(duì)及專業(yè)的網(wǎng)站設(shè)計(jì)師團(tuán)隊(duì)。

for (var i = 0; i < 5; i++) {
      setTimeout(function () {
        console.log(i)
      }, i * 1000);
    }
    console.log(i);

什么?這不就是我很久之前看到的先打印一個5,再打印一個5,之后每隔一秒就打印一個5,直到打印完6個5的實(shí)現(xiàn)方法嗎?那么問題來了,如果我要依次打印0,1,2,3,4,5的話我該怎么辦,其實(shí)在這之前我就知道有這兩個方法:一個是這樣:

function log(i){
setTimeout(function(){
console.log(i)
},i*1000)
};
for (var i = 0; i < 5; i++) {
      log(i) ;
    }
    console.log(i);

   還有一個是這樣:

for(var i=0;i<5;i++){
(function(e){
setTimeout(function(){
console.log(e)
},i*1000);
})(i);
};
console.log(i);

不怕笑話,在這之前我是沒搞懂這兩個函數(shù)真正意義上的作用是用來干嘛的,只強(qiáng)迫自己這樣記住這樣修改就可以了,但是現(xiàn)在不行啊,我有強(qiáng)迫癥??!于是,我慢慢分析了一下,發(fā)現(xiàn)上面那段代碼可以分離成這樣:

i=0時;滿足條件;

setTimeout(function(){
console.log(i)
},0*1000);

i=1時;滿足條件;

setTimeout(function(){
console.log(i)
},1*1000);

i=2時;滿足條件;

setTimeout(function(){
console.log(i)
},2*1000);

i=3時;滿足條件;

setTimeout(function(){
console.log(i)
},3*1000);

i=4時;滿足條件;

setTimeout(function(){
console.log(i)
},4*1000);

i=5時,不滿足條件,跳出循環(huán),接著執(zhí)行for循環(huán)后面的console.log(i),打印5;最后依次每秒打印5;

真有意思,為什么setTimeout里面的console.log會是后于for循環(huán)外面的console.log執(zhí)行呢?直到我認(rèn)識到了這個單詞=>"隊(duì)列", 隊(duì)列又有宏任務(wù)隊(duì)列(Macro Task)以及微任務(wù)隊(duì)列(Micro Task)之分 ,在javascript中:

macro-task包括:script(整體代碼), setTimeout , setInterval, setImmediate, I/O, UI rendering。

micro-task包括:process.nextTick, Promises , Object.observe, MutationObserver

上面函數(shù)的setTimeout就屬于宏任務(wù)

在js中,事件循環(huán)的順序是從script開始第一次循環(huán),隨后全局上下文進(jìn)入函數(shù)調(diào)用棧,碰到macro-task就將其交給處理它的模塊處理完之后將回調(diào)函數(shù)放進(jìn)macro-task的隊(duì)列之中,碰到micro-task也是將其回調(diào)函數(shù)放進(jìn)micro-task的隊(duì)列之中。直到函數(shù)調(diào)用棧清空只剩全局執(zhí)行上下文,然后開始執(zhí)行所有的micro-task。 當(dāng)所有可執(zhí)行的micro-task執(zhí)行完畢之后。循環(huán)再次執(zhí)行macro-task中的一個任務(wù)隊(duì)列 ,執(zhí)行完之后再執(zhí)行所有的micro-task,就這樣一直循環(huán)。

這就是為什么setTimeout里面的console.log會是后于for循環(huán)外面的console.log執(zhí)行,在函數(shù)執(zhí)行上下文中,seiTimeout函數(shù)會被放到處理他的macro-task的隊(duì)列之中,所以循環(huán)的時候setTimeout里面的function是不會被執(zhí)行的,而是等到所有整體代碼(非隊(duì)列)跑完之后才會執(zhí)行隊(duì)列中的函數(shù);寫到這里,可能會有點(diǎn)懵逼,其實(shí)我也有點(diǎn)懵逼,哈哈哈?。?/p>

為了加深理解,還可以試試在里面加入Promise,于是就有了這個:

(function copy() {
  setTimeout(function() {console.log(4)}, 0);
  new Promise(function executor(resolve) {
    console.log(1);
    for( var i=0 ; i<10000 ; i++ ) {
      i == 9999 && resolve();
    }
    console.log(2);
  }).then(function() {
    console.log(5);
  });
  console.log(3);
})()

解釋一下=>

1.首先,script任務(wù)源先執(zhí)行,全局上下文入棧。

2.script任務(wù)源的代碼在執(zhí)行時遇到setTimeout,作為一個macro-task,將其回調(diào)函數(shù)放入自己的隊(duì)列之中。

3.script任務(wù)源的代碼在執(zhí)行時遇到Promise實(shí)例。Promise構(gòu)造函數(shù)中的第一個參數(shù)是在當(dāng)前任務(wù)直接執(zhí)行不會被放入隊(duì)列之中,因此此時輸出 1 。

4.在for循環(huán)里面遇到resolve函數(shù),函數(shù)入棧執(zhí)行之后出棧,此時Promise的狀態(tài)變成Fulfilled。代碼接著執(zhí)行遇到console.log(2),輸出2。

5.接著執(zhí)行,代碼遇到then方法,其回調(diào)函數(shù)作為micro-task入棧,進(jìn)入Promise的任務(wù)隊(duì)列之中,此時Promise的then 里面的function回調(diào)函數(shù)跟setTimeout里面的function回調(diào)函數(shù)有著異曲同工之意,都會被放到各自的任務(wù)隊(duì)列中,

直到函數(shù)上下文即script中所有的非隊(duì)列代碼執(zhí)行完畢后再執(zhí)行,而且微任務(wù)隊(duì)列優(yōu)先于宏任務(wù)隊(duì)列被處理,

  總體順序?yàn)?上下文非隊(duì)列代碼>微任務(wù)隊(duì)列回調(diào)函數(shù)代碼>宏任務(wù)隊(duì)列回調(diào)函數(shù)代碼

6.代碼接著執(zhí)行,此時遇到console.log(3),輸出3。

7.輸出3之后第一個宏任務(wù)script的代碼執(zhí)行完畢,這時候開始開始執(zhí)行所有在隊(duì)列之中的micro-task。then的回調(diào)函數(shù)入棧執(zhí)行完畢之后出棧,這時候輸出5

8.這時候所有的micro-task執(zhí)行完畢,第一輪循環(huán)結(jié)束。第二輪循環(huán)從setTimeout的任務(wù)隊(duì)列開始,setTimeout的回調(diào)函數(shù)入棧執(zhí)行完畢之后出棧,此時輸出4。

最后,為了加深理解,再上一段代碼:

console.log('golb1');
setTimeout(function() {
  console.log('timeout1');
  new Promise(function(resolve) {
    console.log('timeout1_promise');
    resolve();
    setTimeout(function(){
      console.log('time_timeout')
    });  
  }).then(function() {
    console.log('timeout1_then')
  })
  setTimeout(function() {
   console.log('timeout1_timeout1');
  });
})
new Promise(function(resolve) {
  console.log('glob1_promise');
  resolve();
  setTimeout(function(){
     console.log('prp_timeout')
    });
}).then(function() { console.log('glob1_then') })

如果你的執(zhí)行結(jié)果是:golb1=>glob1_promise=>glob1_then=>timeout1=>timeout1_promise=>timeout1_then=>prp_timeout=>time_timeout=>timeout1_timeout1,

可能異步隊(duì)列算是入門了吧!~~上面的代碼看起來有點(diǎn)雜亂,可能用asyns搭配await改造一下會更好,但是這或多或少是鄙人從setTimeout中得到的見解吧

總結(jié)

以上所述是小編給大家介紹的從setTimeout看js函數(shù)執(zhí)行過程,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對創(chuàng)新互聯(lián)網(wǎng)站的支持!


分享標(biāo)題:從setTimeout看js函數(shù)執(zhí)行過程
網(wǎng)頁URL:http://weahome.cn/article/jiiiid.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部