国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

前端校招準備系列--js中的setTimeout到底是什么?

Godtoy / 3553人閱讀

摘要:瀏覽器是多進程的,而瀏覽器的內核渲染進程是多線程的。如果已經將回調函數放進任務隊列,但是主線程正在執行一個非常耗時的任務,當這個任務執行完畢后,主線程去任務隊列中取任務,這個時候,就會出現連續執行的情況,也就是說相當于失效了。

前言

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

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

??setInterval()是按照指定的周期來調用定時器,方法會不斷的調用定時器,直到使用clearInterval()停止或者窗口關閉

語法

??setInterval(code,millisec,lang)

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

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

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

實例

??通過setInterval實現時鐘效果









??效果圖:

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

??顧名思義,這個定時器只會執行一次,和setInterval()的區別就在這兒了,正是因為如此,setInterval()才需要使用clearInterval方法去取消定時器

語法

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

實例

??點擊按鈕3秒后彈出“Hello”





菜鳥教程(runoob.com)



點擊按鈕,在等待 3 秒后彈出 "Hello"。

??效果圖:

取消定時器
介紹

??使用計時器ID來取消計時器回調的發生,每個計時器都會返回一個id,是為了取消定時器的方法可以獲取到相應的計數器。

clearInterval(id)

clearTimeout(id)

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

??我們都知道,js是單線程語言,所有的多線程都是假象,都是單線程模擬出來的。瀏覽器是多進程的,而瀏覽器的內核(渲染進程)是多線程的。不理解這句話的可以去看看這篇文章。
??渲染進程中有一個js引擎線程,這個線程是用來處理javaScript腳本的(例如chrome的V8引擎),而我們一直說的javaScript是單線程的就是因為這個。
??那么問題來了,既然js是單線程的,那setTimeout的異步是怎么實現的呢?js在解析腳本的時候,會將任務分為兩大類,同步任務和異步任務,它們在解析時會進入不同的場所執行。

同步任務:會進入主線程的執行棧,也就是js引擎線程管理的地方,按照順序執行

異步任務:進入Event Table中,并注冊函數,當回調函數的條件滿足時,就會將回調函數放進Event Queue中,也就是任務隊列中。

??當主線程中的任務執行完畢后,也就是執行棧為空時,就會去任務隊列中看有沒有事件,如果有的話,就進入主線程執行,一直這樣循環下去,這就是事件循環機制了,可以參照下面的圖理解一下:

??也許你對事件循環機制的過程還是不太明白,那么我再解釋清楚一點。例如下面這個例子:

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

執行過程:

開始解析,遇到console.log,是同步任務,進入主線程,直接執行,打印start;

往下走,遇到setTimeout,是異步任務,進入Event Table,并注冊回調函數;

再往下走,遇到console.log,直接執行,打印end

5s后,將回調函數放進Event Queue,此時執行棧剛好為空,主線程會去任務隊列中取出這個回調函數,執行,打印setTimeout

??ps:

第1,3步都是js引擎線程干的事情,主線程執行任務;

第2步是渲染進程中的事件觸發線程(專門管理任務隊列的)管理;

第4步是定時器線程控制的(也就是setTiemout和setInterval所在的進程),定時器線程專門用來控制什么時候將回調函數放進任務隊列。

??如果看懂了上面的例子,就知道其實setTimeout的第二個參數其實并不能準確的控制多少秒后執行里面的函數,而是控制多少秒后將這個函數放進任務隊列中;這樣也就同樣可以解釋,為什么有時候明明設置的是2秒之后執行,卻要等不止2秒(因為很有可能定時線程將回調函數放進任務隊列后,主線程還在執行執行棧中的任務,需要執行棧中的任務全部執行完后才會去任務隊列中取任務)。
??這樣就會引發一個問題,我們知道setInterval是隔一定的時間執行一次,現在理解了原理后,就知道其實是隔一定的時間定時器線程將回調函數放進任務隊列中。如果已經將回調函數放進任務隊列,但是主線程正在執行一個非常耗時的任務,當這個任務執行完畢后,主線程去任務隊列中取任務,這個時候,就會出現連續執行的情況,也就是說setInterval相當于失效了。

setTimeout基礎篇

??這一部分主要是針對在事件循環機制中setTimeout調順序進行舉例子,如果能夠輕松的將例子看懂,就說明你是真的懂了事件循環機制的一部分,為什么說是一部分呢,因為還有一個宏任務和微任務的知識點還沒有涉及到,后面的進階篇就會涉及到啦!

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

打印結果:(如果前面看懂了的同學應該就會明白為什么)

分析:其實和上面那個例子時一樣的,只是這個0會給我們一種會立即執行的假象,這個0是說明定時器線程會立即將回調函數放進任務隊列而已,主線程還是會將執行棧中的兩個同步任務執行完成后再去任務隊列中取任務,所以執行順序和這里的秒數無關。而且即使執行棧為空,也不會0秒就執行,因為HTML的標準規定,setTimeout不超過4ms按照4ms來計算。

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

打印結果:(仔細對比與例1的區別)

分析:細心的同學會發現,我將回調函數改成了立即執行函數,就改變了執行的順序。首先我們需要明確的是setTimeout的第一個參數是指函數的返回值,這里回調函數為立即執行函數時,返回值就是undefined了,所以會直接執行立即執行函數,也就是立即打印setTimeout,而真正的setTimeout函數就相當于沒起作用。

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

sleep(10000000)//偽代碼,表示這個函數要執行很久很久

打印結果:
這個結果不說也知道,肯定會打印出setTimeout的,但是重點卻不在這兒~
重點在于,這個setTimeout是隔很久很久打印出來的,遠遠超過了3秒,這個例子也是很明確的體現了js的事件循環機制。

setTimeout進階篇

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

難度:O

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

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

答案:沒錯,你沒有看錯,就是一個簡單的循環,就像你想的那樣,連續輸出0,1,2,3,4

難度:OO

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

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

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

難度:OOO

問題:如果想輸出0,1,2,3,4應該怎么改?
分析:
??出現上一題的情況主要是因為在setTimeout的回調函數中并沒有保存每次循環i的值,最后執行的時候,得到的i就是最后更新的i了(即為5),所以要解決這個問題,思路是要在回調函數中保存每次for循環中的i值。

解決方案1:使用es6中let代替var
分析:let是es6中新增的內容,作用和var一樣,都是用來定義變量,但是最大的差別就是let會形成塊級作用域,在本例中,就是每次循環,都會產生一個作用域,在該作用域中的變量是一個固定值,下次i變化時不會對這個i產生影響,也就是達到了我們的目標。

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

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

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

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

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

解決方案3:將回調函數改成立即執行函數
分析:這個解決方案其實不是太好,如果要求是每隔1秒輸出一個數字,這個方法就不適用了;這個方法會立馬輸出0,1,2,3,4,原因結合基礎篇應該就明白了

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

??這一部分會涉及到promise,事件循環機制,宏任務和微任務的內容,算是比較難的部分了,如果覺得比較難看懂,最好先去補一下基礎知識,我這里就簡單介紹一下。

promise對象

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

宏任務和微任務

宏任務:可以理解成將代碼塊走一遍的過程,setTimeout和promise都是宏任務,現在不理解沒關系,后面會通過例子幫助理解

微任務:是在宏任務執行完成之后執行的,也是有相應的微任務隊列存放微任務,比如promise中的then就是微任務

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

    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);

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

分析:

進入宏任務(從第一行到最后一行執行一遍的過程),碰到setTimeout,將setTimeout放進事件隊列中;

碰到promise,執行console,打印2;

經過循環后,執行console,打印3

到了then,由于then是微任務,會在宏任務執行完成后執行,放進微任務隊列;

遇到console,打印5;

至此,第一次的宏任務執行完成,接下來執行微任務隊列中的then,打印4;

現在執行棧中的任務都執行完了,現在就要去事件隊列中取事件,此時執行setTimeout這個宏任務,打印1

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

總結

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

??如果你覺得還不錯,就請給個贊吧~

參考文章

關于setTimeout的面試題
js事件執行機制
從瀏覽器進程到js線程的詳解
強烈推薦js進階系列

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/99372.html

相關文章

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

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

    jeffrey_up 評論0 收藏0
  • "雙非"應屆生校招如何獲得大廠青睞?(內附前端大廠面經+技術崗超全求職攻略)

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

    lindroid 評論0 收藏0
  • 前端校招準備系列--使用js實現鏈表的操作

    摘要:思路查找倒數第個節點,可以看做是查找正序第個節點可以根據第一題的結果取數組的第個節點使用思路輸入一個鏈表,反轉鏈表后,輸出新鏈表的表頭。 前言 ??在寫項目的時候會發現,并沒有使用很多關于鏈表的東西,大多數情況使用的都是數組,但是由于在準備校招,很多公司都會考到這個問題,所以準備對鏈表的相關操作進行總結,并對其中的重難點進行強調,最后還會附加幾道關于鏈表的算法題,那么現在就開始吧! ...

    fuyi501 評論0 收藏0
  • 2018.11.19秋招末第二波前端實習/校招小結

    摘要:背景個人背景就讀于東北某普通二本院校計算機軟件工程專業,現大四,北京實習前端方向,自學,技術棧時間背景大概是在月日準備好簡歷開始投遞秋招差不多已經結束招聘崗位不多,投遞對象為大一些的互聯網公司事件背景第一個入職的是好未來的前端實習崗,待遇工 背景 個人背景 就讀于東北某普通二本院校計算機軟件工程專業,現大四,北京實習 前端方向,自學,vue技術棧 時間背景 大概是在11月9日準備...

    suxier 評論0 收藏0
  • 2018.11.19秋招末第二波前端實習/校招小結

    摘要:背景個人背景就讀于東北某普通二本院校計算機軟件工程專業,現大四,北京實習前端方向,自學,技術棧時間背景大概是在月日準備好簡歷開始投遞秋招差不多已經結束招聘崗位不多,投遞對象為大一些的互聯網公司事件背景第一個入職的是好未來的前端實習崗,待遇工 背景 個人背景 就讀于東北某普通二本院校計算機軟件工程專業,現大四,北京實習 前端方向,自學,vue技術棧 時間背景 大概是在11月9日準備...

    canger 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<