目錄
'一次'定時器:setTimeout()
介紹 " >介紹
語法" >語法
取消計時器
實例" >實例
setTimeout的執行順序到底是怎麼樣的?
setTimeout基础篇
例3
setTimeout进阶篇
难度:O
难度:OO
难度:OOO
难度:OOOO
promise对象
宏任务和微任务
首頁 web前端 js教程 面試:JavaScript中的setTimeout到底是什麼?

面試:JavaScript中的setTimeout到底是什麼?

Nov 26, 2018 pm 03:33 PM
javascript

這篇文章帶給大家的內容是關於面試:JavaScript中的setTimeout到底是什麼? ,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

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

計時器的介紹

#js中有哪些定時器?

週期定時器:setInterval()

介紹

setInterval()是依照指定的週期來呼叫定時器,方法會不斷的呼叫定時器,直到使用clearInterval()停止或視窗關閉。

語法

setInterval(code,millisec,lang)

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

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

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

實例

透過setInterval實作時脈效果



<input>
<script>
//每隔1秒执行一次clock方法
var int=self.setInterval("clock()",1000);
function clock()
{
var d=new Date();
var t=d.toLocaleTimeString();
document.getElementById("clock").value=t;
}
</script>
<!-- 设置一个按钮,点击按钮即停止定时器 -->
<button>停止</button>

登入後複製

效果圖:

面試:JavaScript中的setTimeout到底是什麼?

'一次'定時器:setTimeout()

介紹

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

語法

  setTimeout(code,millisec,lang)    ps:每個參數的意義和setInterval()的皆相同

實例

  點擊按鈕3秒後彈出「Hello」

nbsp;html>


<meta>
<title>菜鸟教程(runoob.com)</title>



<p>点击按钮,在等待 3 秒后弹出 "Hello"。</p>
<button>点我</button>

<script>
function myFunction()
{
    setTimeout(function(){alert("Hello")},3000);
}
</script>


登入後複製

效果圖:

面試:JavaScript中的setTimeout到底是什麼?

取消計時器

##  使用計時器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中,也就是任務佇列中。

  當主執行緒中的任務執行完畢後,也就是執行端為空時,就會去任務佇列中看有沒有事件,如果有的話,就進入主執行緒執行,一直這樣循環下去,這就是事件循環機制了,可以參考下面的圖來理解一下:

面試:JavaScript中的setTimeout到底是什麼?

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

   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')
登入後複製

打印结果:(如果前面看懂了的同学应该就会明白为什么)

面試:JavaScript中的setTimeout到底是什麼?

分析:其实和上面那个例子时一样的,只是这个0会给我们一种会立即执行的假象,这个0是说明定时器线程会立即将回调函数放进任务队列而已,主线程还是会将执行栈中的两个同步任务执行完成后再去任务队列中取任务,所以执行顺序和这里的秒数无关。而且即使执行栈为空,也不会0秒就执行,因为HTML的标准规定,setTimeout不超过4ms按照4ms来计算。

例2

  console.log('start')
  setTimeout(function(){
    console.log('setTimeout')
  }(),0)
  console.log('end')
登入後複製

打印结果:(仔细对比与例1的区别)

面試:JavaScript中的setTimeout到底是什麼?

分析:细心的同学会发现,我将回调函数改成了立即执行函数,就改变了执行的顺序。首先我们需要明确的是setTimeout的第一个参数是指函数的返回值,这里回调函数为立即执行函数时,返回值就是undefined了,所以会直接执行立即执行函数,也就是立即打印setTimeout,而真正的setTimeout函数就相当于没起作用。

例3

setTimeout(() => {
   console.log('setTimeout')
},3000)

sleep(10000000)//伪代码,表示这个函数要执行很久很久
登入後複製

打印结果:
这个结果不说也知道,肯定会打印出setTimeout的,但是重点却不在这儿~
重点在于,这个setTimeout是隔很久很久打印出来的,远远超过了3秒,这个例子也是很明确的体现了js的事件循环机制。

setTimeout进阶篇

  这一部分相对于基础篇,加上了作用域以及其他也是比较难以理解的东西,可能还需要补充一些其他知识才会明白,我会尽量讲清楚,也会把我看的参考文章放在下面。
  受到一篇文章的启发,我们以循序渐进的方式来阐述

难度:O

问题:以下代码输出的是什么?

for(var i = 0;i <p><strong>答案:</strong>没错,你没有看错,就是一个简单的循环,就像你想的那样,连续输出0,1,2,3,4</p><h3 id="难度-OO">难度:OO</h3><p><strong>问题:</strong>以下代码输出的是什么?如果把时间改为1000*i输出的又是什么?</p><pre class="brush:php;toolbar:false">for(var i = 0;i <p><strong>答案:</strong><br>  时间为1000时,1秒后会连续输出5个5;时间为1000*i时,会每隔一秒输出一个5,一共5个5<br><strong>分析:</strong><br>  由上面的事件循环机制我们知道,setTimeout是异步事件,会放在事件队列中等着主线程来执行,这个时候for循环中的i已经变成了5,由于定时器线程是在1秒后直接将5个setTimeout事件放进事件队列中,所以主线程在执行的时候就没有间隔了;当时间乘上一个i时,定时器会隔1秒将setTimeout事件放入队列,就会出现每隔一秒输出一个5的情况。</p><h3 id="难度-OOO">难度:OOO</h3><p><strong>问题:</strong>如果想输出0,1,2,3,4应该怎么改?<br><strong>分析:</strong><br>  出现上一题的情况主要是因为在setTimeout的回调函数中并没有保存每次循环i的值,最后执行的时候,得到的i就是最后更新的i了(即为5),所以要解决这个问题,思路是要在回调函数中保存每次for循环中的i值。</p><p><strong>解决方案1:</strong>使用es6中let代替var<br><strong>分析:</strong>let是es6中新增的内容,作用和var一样,都是用来定义变量,但是最大的差别就是let会形成块级作用域,在本例中,就是每次循环,都会产生一个作用域,在该作用域中的变量是一个固定值,下次i变化时不会对这个i产生影响,也就是达到了我们的目标。</p><pre class="brush:php;toolbar:false">for(let i = 0;i <p><strong>解决方案2:</strong>使用闭包<br><strong>分析:</strong>就是直接在setTimeout函数的外面套一层立即执行函数,并将i值作为参数传到匿名函数中(这里的匿名函数也可以是命名函数),然后由于setTimeout中回调函数用到了匿名函数中的i,就会形成闭包。</p><pre class="brush:php;toolbar:false">for(var i = 0;i <p><strong>延伸:</strong>将代码变成下面这样会输出什么?(去掉匿名函数中的i)<br><strong>分析:</strong>这里会输出5个5,也就是闭包没有起作用,根本原因是i并没有传进去,打印的还是最后的i</p><pre class="brush:php;toolbar:false">for (var i = 0; i <p><strong>解决方案3:</strong>将回调函数改成立即执行函数<br><strong>分析:</strong>这个解决方案其实不是太好,如果要求是每隔1秒输出一个数字,这个方法就不适用了;这个方法会立马输出0,1,2,3,4,原因结合基础篇应该就明白了</p><pre class="brush:php;toolbar:false">for (var i = 0; i <h3 id="难度-OOOO">难度:OOOO</h3><p>  这一部分会涉及到promise,事件循环机制,宏任务和微任务的内容,算是比较难的部分了,如果觉得比较难看懂,最好先去补一下基础知识,我这里就简单介绍一下。</p><h4 id="promise对象">promise对象</h4><p>我这里就不详细讲了。</p><h4 id="宏任务和微任务">宏任务和微任务</h4>
登入後複製
  • 宏任务:可以理解成将代码块走一遍的过程,setTimeout和promise都是宏任务,现在不理解没关系,后面会通过例子帮助理解

  • 微任务:是在宏任务执行完成之后执行的,也是有相应的微任务队列存放微任务,比如promise中的then就是微任务

面試:JavaScript中的setTimeout到底是什麼?

问题:以下代码输出的是什么?

    setTimeout(function () {
      console.log(1)
    }, 0);
    new Promise(function executor(resolve) {
      console.log(2);
      for (var i = 0; i <p><strong>答案:</strong>(是不是很懵,为什么会是这样,下面看我的分析你就知道了)</p><p style="text-align: center;"><span class="img-wrap"><img src="/static/imghw/default1.png" data-src="https://img.php.cn//upload/image/617/114/318/1543217488584753.png" class="lazy" title="1543217488584753.png" alt="面試:JavaScript中的setTimeout到底是什麼?"></span></p><p><strong>分析:</strong></p><ol class=" list-paddingleft-2">
<li><p>进入宏任务(从第一行到最后一行执行一遍的过程),碰到setTimeout,将setTimeout放进事件队列中;</p></li>
<li><p>碰到promise,执行console,<strong>打印2</strong>;</p></li>
<li><p>经过循环后,执行console,<strong>打印3</strong>;</p></li>
<li><p>到了then,由于then是微任务,会在宏任务执行完成后执行,放进微任务队列;</p></li>
<li><p>遇到console,<strong>打印5</strong>;</p></li>
<li><p>至此,第一次的宏任务执行完成,接下来执行微任务队列中的then,<strong>打印4</strong>;</p></li>
<li><p>现在执行栈中的任务都执行完了,现在就要去事件队列中取事件,此时执行setTimeout这个宏任务,<strong>打印1</strong>;</p></li>
</ol><p><strong>宏任务微任务与同步事件异步事件的关系:</strong><br>  这些词都是用来描述事件的,只是从不同的角度来描述,就像是胖子矮子与男生女生之间的联系</p><p class="comments-box-content"><br></p><p>		</p>
登入後複製

以上是面試:JavaScript中的setTimeout到底是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

See all articles