成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

前端校招準(zhǔn)備系列--js中的setTimeout到底是什么?

Godtoy / 3551人閱讀

摘要:瀏覽器是多進(jìn)程的,而瀏覽器的內(nèi)核渲染進(jìn)程是多線程的。如果已經(jīng)將回調(diào)函數(shù)放進(jìn)任務(wù)隊(duì)列,但是主線程正在執(zhí)行一個(gè)非常耗時(shí)的任務(wù),當(dāng)這個(gè)任務(wù)執(zhí)行完畢后,主線程去任務(wù)隊(duì)列中取任務(wù),這個(gè)時(shí)候,就會(huì)出現(xiàn)連續(xù)執(zhí)行的情況,也就是說相當(dāng)于失效了。

前言

??在刷筆試題的時(shí)候,經(jīng)常會(huì)碰到setTimeout的問題,只知道這個(gè)是設(shè)置定時(shí)器;但是考察的重點(diǎn)一般是在一個(gè)方法中包含了定時(shí)器,定時(shí)器中的打印和方法中打印的執(zhí)行順序問題,也許我說的有點(diǎn)兒難懂,下面就來看看setTimeout到底是什么吧!

定時(shí)器的介紹 js中有哪些定時(shí)器? 周期定時(shí)器:setInterval()
介紹

??setInterval()是按照指定的周期來調(diào)用定時(shí)器,方法會(huì)不斷的調(diào)用定時(shí)器,直到使用clearInterval()停止或者窗口關(guān)閉

語(yǔ)法

??setInterval(code,millisec,lang)

code:要執(zhí)行的方法體(必選)

millisec:每隔多少毫秒執(zhí)行一次(單位是毫秒,如果設(shè)置為5000,即每5秒執(zhí)行一次)(必選)

lang:指使用的語(yǔ)言(可選)

實(shí)例

??通過setInterval實(shí)現(xiàn)時(shí)鐘效果









??效果圖:

‘一次性’定時(shí)器:setTimeout()
介紹

??顧名思義,這個(gè)定時(shí)器只會(huì)執(zhí)行一次,和setInterval()的區(qū)別就在這兒了,正是因?yàn)槿绱耍瑂etInterval()才需要使用clearInterval方法去取消定時(shí)器

語(yǔ)法

??setTimeout(code,millisec,lang)????ps:每個(gè)參數(shù)的含義和setInterval()的均相同

實(shí)例

??點(diǎn)擊按鈕3秒后彈出“Hello”





菜鳥教程(runoob.com)



點(diǎn)擊按鈕,在等待 3 秒后彈出 "Hello"。

??效果圖:

取消定時(shí)器
介紹

??使用計(jì)時(shí)器ID來取消計(jì)時(shí)器回調(diào)的發(fā)生,每個(gè)計(jì)時(shí)器都會(huì)返回一個(gè)id,是為了取消定時(shí)器的方法可以獲取到相應(yīng)的計(jì)數(shù)器。

clearInterval(id)

clearTimeout(id)

實(shí)例
//設(shè)置超時(shí)調(diào)用
var timeoutId = setTimeout(function (){
    alert("hello World");
    },1000);
//取消掉用的代碼
clearTimeout(timeoutId);
setTimeout的執(zhí)行順序到底是怎樣的?

??我們都知道,js是單線程語(yǔ)言,所有的多線程都是假象,都是單線程模擬出來的。瀏覽器是多進(jìn)程的,而瀏覽器的內(nèi)核(渲染進(jìn)程)是多線程的。不理解這句話的可以去看看這篇文章。
??渲染進(jìn)程中有一個(gè)js引擎線程,這個(gè)線程是用來處理javaScript腳本的(例如chrome的V8引擎),而我們一直說的javaScript是單線程的就是因?yàn)檫@個(gè)。
??那么問題來了,既然js是單線程的,那setTimeout的異步是怎么實(shí)現(xiàn)的呢?js在解析腳本的時(shí)候,會(huì)將任務(wù)分為兩大類,同步任務(wù)和異步任務(wù),它們?cè)诮馕鰰r(shí)會(huì)進(jìn)入不同的場(chǎng)所執(zhí)行。

同步任務(wù):會(huì)進(jìn)入主線程的執(zhí)行棧,也就是js引擎線程管理的地方,按照順序執(zhí)行

異步任務(wù):進(jìn)入Event Table中,并注冊(cè)函數(shù),當(dāng)回調(diào)函數(shù)的條件滿足時(shí),就會(huì)將回調(diào)函數(shù)放進(jìn)Event Queue中,也就是任務(wù)隊(duì)列中。

??當(dāng)主線程中的任務(wù)執(zhí)行完畢后,也就是執(zhí)行棧為空時(shí),就會(huì)去任務(wù)隊(duì)列中看有沒有事件,如果有的話,就進(jìn)入主線程執(zhí)行,一直這樣循環(huán)下去,這就是事件循環(huán)機(jī)制了,可以參照下面的圖理解一下:

??也許你對(duì)事件循環(huán)機(jī)制的過程還是不太明白,那么我再解釋清楚一點(diǎn)。例如下面這個(gè)例子:

   console.log("start")
   setTimeout(function(){
     console.log("setTimeout")
   },5000)
   console.log("end")

執(zhí)行過程:

開始解析,遇到console.log,是同步任務(wù),進(jìn)入主線程,直接執(zhí)行,打印start;

往下走,遇到setTimeout,是異步任務(wù),進(jìn)入Event Table,并注冊(cè)回調(diào)函數(shù);

再往下走,遇到console.log,直接執(zhí)行,打印end;

5s后,將回調(diào)函數(shù)放進(jìn)Event Queue,此時(shí)執(zhí)行棧剛好為空,主線程會(huì)去任務(wù)隊(duì)列中取出這個(gè)回調(diào)函數(shù),執(zhí)行,打印setTimeout

??ps:

第1,3步都是js引擎線程干的事情,主線程執(zhí)行任務(wù);

第2步是渲染進(jìn)程中的事件觸發(fā)線程(專門管理任務(wù)隊(duì)列的)管理;

第4步是定時(shí)器線程控制的(也就是setTiemout和setInterval所在的進(jìn)程),定時(shí)器線程專門用來控制什么時(shí)候?qū)⒒卣{(diào)函數(shù)放進(jìn)任務(wù)隊(duì)列。

??如果看懂了上面的例子,就知道其實(shí)setTimeout的第二個(gè)參數(shù)其實(shí)并不能準(zhǔn)確的控制多少秒后執(zhí)行里面的函數(shù),而是控制多少秒后將這個(gè)函數(shù)放進(jìn)任務(wù)隊(duì)列中;這樣也就同樣可以解釋,為什么有時(shí)候明明設(shè)置的是2秒之后執(zhí)行,卻要等不止2秒(因?yàn)楹苡锌赡芏〞r(shí)線程將回調(diào)函數(shù)放進(jìn)任務(wù)隊(duì)列后,主線程還在執(zhí)行執(zhí)行棧中的任務(wù),需要執(zhí)行棧中的任務(wù)全部執(zhí)行完后才會(huì)去任務(wù)隊(duì)列中取任務(wù))。
??這樣就會(huì)引發(fā)一個(gè)問題,我們知道setInterval是隔一定的時(shí)間執(zhí)行一次,現(xiàn)在理解了原理后,就知道其實(shí)是隔一定的時(shí)間定時(shí)器線程將回調(diào)函數(shù)放進(jìn)任務(wù)隊(duì)列中。如果已經(jīng)將回調(diào)函數(shù)放進(jìn)任務(wù)隊(duì)列,但是主線程正在執(zhí)行一個(gè)非常耗時(shí)的任務(wù),當(dāng)這個(gè)任務(wù)執(zhí)行完畢后,主線程去任務(wù)隊(duì)列中取任務(wù),這個(gè)時(shí)候,就會(huì)出現(xiàn)連續(xù)執(zhí)行的情況,也就是說setInterval相當(dāng)于失效了。

setTimeout基礎(chǔ)篇

??這一部分主要是針對(duì)在事件循環(huán)機(jī)制中setTimeout調(diào)順序進(jìn)行舉例子,如果能夠輕松的將例子看懂,就說明你是真的懂了事件循環(huán)機(jī)制的一部分,為什么說是一部分呢,因?yàn)檫€有一個(gè)宏任務(wù)和微任務(wù)的知識(shí)點(diǎn)還沒有涉及到,后面的進(jìn)階篇就會(huì)涉及到啦!

例1
  console.log("start")
  setTimeout(function(){
    console.log("setTimeout")
  },0)
  console.log("end")

打印結(jié)果:(如果前面看懂了的同學(xué)應(yīng)該就會(huì)明白為什么)

分析:其實(shí)和上面那個(gè)例子時(shí)一樣的,只是這個(gè)0會(huì)給我們一種會(huì)立即執(zhí)行的假象,這個(gè)0是說明定時(shí)器線程會(huì)立即將回調(diào)函數(shù)放進(jìn)任務(wù)隊(duì)列而已,主線程還是會(huì)將執(zhí)行棧中的兩個(gè)同步任務(wù)執(zhí)行完成后再去任務(wù)隊(duì)列中取任務(wù),所以執(zhí)行順序和這里的秒數(shù)無關(guān)。而且即使執(zhí)行棧為空,也不會(huì)0秒就執(zhí)行,因?yàn)镠TML的標(biāo)準(zhǔn)規(guī)定,setTimeout不超過4ms按照4ms來計(jì)算。

例2
  console.log("start")
  setTimeout(function(){
    console.log("setTimeout")
  }(),0)
  console.log("end")

打印結(jié)果:(仔細(xì)對(duì)比與例1的區(qū)別)

分析:細(xì)心的同學(xué)會(huì)發(fā)現(xiàn),我將回調(diào)函數(shù)改成了立即執(zhí)行函數(shù),就改變了執(zhí)行的順序。首先我們需要明確的是setTimeout的第一個(gè)參數(shù)是指函數(shù)的返回值,這里回調(diào)函數(shù)為立即執(zhí)行函數(shù)時(shí),返回值就是undefined了,所以會(huì)直接執(zhí)行立即執(zhí)行函數(shù),也就是立即打印setTimeout,而真正的setTimeout函數(shù)就相當(dāng)于沒起作用。

例3
setTimeout(() => {
   console.log("setTimeout")
},3000)

sleep(10000000)//偽代碼,表示這個(gè)函數(shù)要執(zhí)行很久很久

打印結(jié)果:
這個(gè)結(jié)果不說也知道,肯定會(huì)打印出setTimeout的,但是重點(diǎn)卻不在這兒~
重點(diǎn)在于,這個(gè)setTimeout是隔很久很久打印出來的,遠(yuǎn)遠(yuǎn)超過了3秒,這個(gè)例子也是很明確的體現(xiàn)了js的事件循環(huán)機(jī)制。

setTimeout進(jìn)階篇

??這一部分相對(duì)于基礎(chǔ)篇,加上了作用域以及其他也是比較難以理解的東西,可能還需要補(bǔ)充一些其他知識(shí)才會(huì)明白,我會(huì)盡量講清楚,也會(huì)把我看的參考文章放在下面。
??受到一篇文章的啟發(fā),我們以循序漸進(jìn)的方式來闡述

難度:O

問題:以下代碼輸出的是什么?

for(var i = 0;i < 5;i++){
    console.log(i)
  }

答案:沒錯(cuò),你沒有看錯(cuò),就是一個(gè)簡(jiǎn)單的循環(huán),就像你想的那樣,連續(xù)輸出0,1,2,3,4

難度:OO

問題:以下代碼輸出的是什么?如果把時(shí)間改為1000*i輸出的又是什么?

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

答案:
??時(shí)間為1000時(shí),1秒后會(huì)連續(xù)輸出5個(gè)5;時(shí)間為1000*i時(shí),會(huì)每隔一秒輸出一個(gè)5,一共5個(gè)5
分析:
??由上面的事件循環(huán)機(jī)制我們知道,setTimeout是異步事件,會(huì)放在事件隊(duì)列中等著主線程來執(zhí)行,這個(gè)時(shí)候for循環(huán)中的i已經(jīng)變成了5,由于定時(shí)器線程是在1秒后直接將5個(gè)setTimeout事件放進(jìn)事件隊(duì)列中,所以主線程在執(zhí)行的時(shí)候就沒有間隔了;當(dāng)時(shí)間乘上一個(gè)i時(shí),定時(shí)器會(huì)隔1秒將setTimeout事件放入隊(duì)列,就會(huì)出現(xiàn)每隔一秒輸出一個(gè)5的情況。

難度:OOO

問題:如果想輸出0,1,2,3,4應(yīng)該怎么改?
分析:
??出現(xiàn)上一題的情況主要是因?yàn)樵趕etTimeout的回調(diào)函數(shù)中并沒有保存每次循環(huán)i的值,最后執(zhí)行的時(shí)候,得到的i就是最后更新的i了(即為5),所以要解決這個(gè)問題,思路是要在回調(diào)函數(shù)中保存每次for循環(huán)中的i值。

解決方案1:使用es6中l(wèi)et代替var
分析:let是es6中新增的內(nèi)容,作用和var一樣,都是用來定義變量,但是最大的差別就是let會(huì)形成塊級(jí)作用域,在本例中,就是每次循環(huán),都會(huì)產(chǎn)生一個(gè)作用域,在該作用域中的變量是一個(gè)固定值,下次i變化時(shí)不會(huì)對(duì)這個(gè)i產(chǎn)生影響,也就是達(dá)到了我們的目標(biāo)。

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

解決方案2:使用閉包
分析:就是直接在setTimeout函數(shù)的外面套一層立即執(zhí)行函數(shù),并將i值作為參數(shù)傳到匿名函數(shù)中(這里的匿名函數(shù)也可以是命名函數(shù)),然后由于setTimeout中回調(diào)函數(shù)用到了匿名函數(shù)中的i,就會(huì)形成閉包。

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

延伸:將代碼變成下面這樣會(huì)輸出什么?(去掉匿名函數(shù)中的i)
分析:這里會(huì)輸出5個(gè)5,也就是閉包沒有起作用,根本原因是i并沒有傳進(jìn)去,打印的還是最后的i

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

解決方案3:將回調(diào)函數(shù)改成立即執(zhí)行函數(shù)
分析:這個(gè)解決方案其實(shí)不是太好,如果要求是每隔1秒輸出一個(gè)數(shù)字,這個(gè)方法就不適用了;這個(gè)方法會(huì)立馬輸出0,1,2,3,4,原因結(jié)合基礎(chǔ)篇應(yīng)該就明白了

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

??這一部分會(huì)涉及到promise,事件循環(huán)機(jī)制,宏任務(wù)和微任務(wù)的內(nèi)容,算是比較難的部分了,如果覺得比較難看懂,最好先去補(bǔ)一下基礎(chǔ)知識(shí),我這里就簡(jiǎn)單介紹一下。

promise對(duì)象

我這里就不詳細(xì)講了,可以看這篇文章

宏任務(wù)和微任務(wù)

宏任務(wù):可以理解成將代碼塊走一遍的過程,setTimeout和promise都是宏任務(wù),現(xiàn)在不理解沒關(guān)系,后面會(huì)通過例子幫助理解

微任務(wù):是在宏任務(wù)執(zhí)行完成之后執(zhí)行的,也是有相應(yīng)的微任務(wù)隊(duì)列存放微任務(wù),比如promise中的then就是微任務(wù)

問題:以下代碼輸出的是什么?

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

答案:(是不是很懵,為什么會(huì)是這樣,下面看我的分析你就知道了)

分析:

進(jìn)入宏任務(wù)(從第一行到最后一行執(zhí)行一遍的過程),碰到setTimeout,將setTimeout放進(jìn)事件隊(duì)列中;

碰到promise,執(zhí)行console,打印2;

經(jīng)過循環(huán)后,執(zhí)行console,打印3;

到了then,由于then是微任務(wù),會(huì)在宏任務(wù)執(zhí)行完成后執(zhí)行,放進(jìn)微任務(wù)隊(duì)列;

遇到console,打印5;

至此,第一次的宏任務(wù)執(zhí)行完成,接下來執(zhí)行微任務(wù)隊(duì)列中的then,打印4;

現(xiàn)在執(zhí)行棧中的任務(wù)都執(zhí)行完了,現(xiàn)在就要去事件隊(duì)列中取事件,此時(shí)執(zhí)行setTimeout這個(gè)宏任務(wù),打印1;

宏任務(wù)微任務(wù)與同步事件異步事件的關(guān)系:
??這些詞都是用來描述事件的,只是從不同的角度來描述,就像是胖子矮子與男生女生之間的聯(lián)系。

總結(jié)

??關(guān)于setTimeout還有很多可以去研究的東西,我這里只是將我目前看到的相關(guān)內(nèi)容進(jìn)行總結(jié),由于涉及的內(nèi)容過多,如果沒有相關(guān)內(nèi)容的基礎(chǔ)可能會(huì)比較難看懂,我也是為了這篇文章看了好多資料,這篇文章拖了大概一周才完工,有什么問題,可以留言告訴我呀!

??如果你覺得還不錯(cuò),就請(qǐng)給個(gè)贊吧~

參考文章

關(guān)于setTimeout的面試題
js事件執(zhí)行機(jī)制
從瀏覽器進(jìn)程到j(luò)s線程的詳解
強(qiáng)烈推薦js進(jìn)階系列

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99372.html

相關(guān)文章

  • "雙非"應(yīng)屆生校招如何獲得大廠青睞?(內(nèi)附前端大廠面經(jīng)+技術(shù)崗超全求職攻略)

    摘要:拿到秋招的同學(xué),如確定入職需與用人單位簽署三方協(xié)議,以保證雙方的利益不受損失。當(dāng)然每個(gè)崗位所要求的側(cè)重點(diǎn)不同,但卻百變不離其宗。方法論要想達(dá)成某個(gè)目標(biāo)都有其特定的方法論,學(xué)習(xí)技術(shù)也不例外,掌握適當(dāng)?shù)膶W(xué)習(xí)方法才能事半功倍。 寫在前面的話 筆者從17年的2月份開始準(zhǔn)備春招,其中遇到不少坑,也意識(shí)到自己走過的彎路。故寫了這篇文章總結(jié)一番,本文適合主動(dòng)學(xué)習(xí)的,對(duì)自己要學(xué)的課程不明確的,對(duì)面試有...

    jeffrey_up 評(píng)論0 收藏0
  • "雙非"應(yīng)屆生校招如何獲得大廠青睞?(內(nèi)附前端大廠面經(jīng)+技術(shù)崗超全求職攻略)

    摘要:拿到秋招的同學(xué),如確定入職需與用人單位簽署三方協(xié)議,以保證雙方的利益不受損失。當(dāng)然每個(gè)崗位所要求的側(cè)重點(diǎn)不同,但卻百變不離其宗。方法論要想達(dá)成某個(gè)目標(biāo)都有其特定的方法論,學(xué)習(xí)技術(shù)也不例外,掌握適當(dāng)?shù)膶W(xué)習(xí)方法才能事半功倍。 寫在前面的話 筆者從17年的2月份開始準(zhǔn)備春招,其中遇到不少坑,也意識(shí)到自己走過的彎路。故寫了這篇文章總結(jié)一番,本文適合主動(dòng)學(xué)習(xí)的,對(duì)自己要學(xué)的課程不明確的,對(duì)面試有...

    lindroid 評(píng)論0 收藏0
  • 前端校招準(zhǔn)備系列--使用js實(shí)現(xiàn)鏈表的操作

    摘要:思路查找倒數(shù)第個(gè)節(jié)點(diǎn),可以看做是查找正序第個(gè)節(jié)點(diǎn)可以根據(jù)第一題的結(jié)果取數(shù)組的第個(gè)節(jié)點(diǎn)使用思路輸入一個(gè)鏈表,反轉(zhuǎn)鏈表后,輸出新鏈表的表頭。 前言 ??在寫項(xiàng)目的時(shí)候會(huì)發(fā)現(xiàn),并沒有使用很多關(guān)于鏈表的東西,大多數(shù)情況使用的都是數(shù)組,但是由于在準(zhǔn)備校招,很多公司都會(huì)考到這個(gè)問題,所以準(zhǔn)備對(duì)鏈表的相關(guān)操作進(jìn)行總結(jié),并對(duì)其中的重難點(diǎn)進(jìn)行強(qiáng)調(diào),最后還會(huì)附加幾道關(guān)于鏈表的算法題,那么現(xiàn)在就開始吧! ...

    fuyi501 評(píng)論0 收藏0
  • 2018.11.19秋招末第二波前端實(shí)習(xí)/校招小結(jié)

    摘要:背景個(gè)人背景就讀于東北某普通二本院校計(jì)算機(jī)軟件工程專業(yè),現(xiàn)大四,北京實(shí)習(xí)前端方向,自學(xué),技術(shù)棧時(shí)間背景大概是在月日準(zhǔn)備好簡(jiǎn)歷開始投遞秋招差不多已經(jīng)結(jié)束招聘崗位不多,投遞對(duì)象為大一些的互聯(lián)網(wǎng)公司事件背景第一個(gè)入職的是好未來的前端實(shí)習(xí)崗,待遇工 背景 個(gè)人背景 就讀于東北某普通二本院校計(jì)算機(jī)軟件工程專業(yè),現(xiàn)大四,北京實(shí)習(xí) 前端方向,自學(xué),vue技術(shù)棧 時(shí)間背景 大概是在11月9日準(zhǔn)備...

    suxier 評(píng)論0 收藏0
  • 2018.11.19秋招末第二波前端實(shí)習(xí)/校招小結(jié)

    摘要:背景個(gè)人背景就讀于東北某普通二本院校計(jì)算機(jī)軟件工程專業(yè),現(xiàn)大四,北京實(shí)習(xí)前端方向,自學(xué),技術(shù)棧時(shí)間背景大概是在月日準(zhǔn)備好簡(jiǎn)歷開始投遞秋招差不多已經(jīng)結(jié)束招聘崗位不多,投遞對(duì)象為大一些的互聯(lián)網(wǎng)公司事件背景第一個(gè)入職的是好未來的前端實(shí)習(xí)崗,待遇工 背景 個(gè)人背景 就讀于東北某普通二本院校計(jì)算機(jī)軟件工程專業(yè),現(xiàn)大四,北京實(shí)習(xí) 前端方向,自學(xué),vue技術(shù)棧 時(shí)間背景 大概是在11月9日準(zhǔn)備...

    canger 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<