從setTimeout簡單瞭解js事件模型

先從一個例子入手:javascript

(function() {
  console.log('開始執行')

  setTimeout(function fun1() {
    console.log('第一個延時函數消息')
  })

  console.log('一條消息')
  
  setTimeout(function fun2() {
    console.log('第二個延時函數消息')
  }, 0)

  console.log('結束')

})();
複製代碼

輸出結果很容易知道:java

//開始執行
//一條消息
//結束
//第一個延時函數消息
//第二個延時函數消息
複製代碼

在js事件模型中,運行時從最早進入隊列的消息開始處理隊列中的消息,這不難理解,但上述代碼爲何setTimeout延時爲0也會延後執行?promise

這是由於在js中,bash

  • 全部的同步任務在主線程上按順序執行,前一個任務執行完畢,才能執行後一個任務
  • 主線程以外有一個任務隊列,像setTimeout,promise.then,await promise這種的異步任務在任務隊列上先按等級再按順序排隊,等級是什麼鬼?異步任務也是分等級的,promise.then排第一梯隊,await promise排第二梯隊,,最後就是setTimeout,按等級排好隊後再按順序排好隊(見下面示例)
  • 當主線程中的同步任務執行完畢後,就會通知任務隊列中的任務:主線程上的同步任務執行好了,大家能夠來主線程了。而後排好隊進入主線程,開始執行異步任務
  • 總的來說就是隻要主線程空了,就會去讀取"任務隊列",這就是JavaScript的運行機制。這個過程會不斷重複。
setTimeout(()=>{
  console.log("11")
})

setTimeout(()=>{
  console.log("12")
},0)

function promise_func(){
  return new Promise((resolve,reject)=>{
      resolve("異步輸出結果")
  })
}

promise_func().then(data=>{
  console.log('then', data)
})

async function fun1(){
  console.log('await1', await promise_func())
}
fun1()

async function fun2(){
  console.log('await2', await promise_func())
}
fun2()

promise_func().then(data=>{
  console.log('then2', data)
})

console.log("22")
複製代碼

打印結果:異步

22
then 異步輸出結果
then2 異步輸出結果
await1 異步輸出結果
await2 異步輸出結果
11
12
複製代碼

事件模型中加入消息隊列神馬的通常來講你不去關心是看不清摸不着的,但根據setTimeout你能夠稍微簡單的感覺到裏面的一些狀況async

很少說,先放一個簡單例子:函數

(function() {
  console.log('開始');

  setTimeout(function cb() {
    console.log('第一個延時器的消息');
  },1001);

  console.log('一條消息');

  setTimeout(function cb1() {
    console.log('第二個延時器的消息');
  }, 1000);

  console.log('結束');
})()
複製代碼

可能你會有點猶豫了,其實結果是:ui

開始
一條消息
結束
第一個延時器的消息
第二個延時器的消息
複製代碼

爲啥第一個延時1.001s比第二個延時1.000s要先執行呢,咱們先從setTimeout提及spa

setTimeout沒跟同步函數一塊兒被加入到消息隊列,而是等待同步消息隊列執行結束開始加入,延遲參數表明消息被實際加入到隊列的最小延遲時間線程

若是隊列中沒有其它消息,在這段延遲時間過去以後,消息會被立刻處理。可是,若是有其它消息,setTimeout 消息必須等待其它消息處理完。

上述代碼中,第一個延時函數被加入到消息隊列,並當即開始執行,等待1.001s後輸出結果,在第一個延時函數加入到隊列並當即執行這一過程當中,第二個延時函數也加入了隊列,這個加入到隊列的過程是須要必定時間的,這個時間取決於cpu的處理速度,固然這個時間是很是短的。

上面是一個簡單例子,咱們誇大一下這個例子,試着讓最後一個延時1秒的函數等待更多的時間再去執行,比第一個延時1.0002s的延時函數還要慢,方案就是在這過程當中讓更多的延時函數加入消息隊列。

(function () {

  console.log('開始')

  setTimeout(function cb() {
    console.log('第一個延時器的消息')
  }, 1002)

  console.log('一條消息')

  for (let i of new Array(1000)) {
    setTimeout(function cb1() {
      console.log('nb')
    }, 2000)
  }

  setTimeout(function cb1() {
    console.log('最後一個延時器的消息')
  }, 1000)

  console.log('結束')
})()
複製代碼

執行結果:

開始
一條消息
結束
第一個延時器的消息
最後一個延時器的消息
nb
nb
...
...
複製代碼

第一個延時函數被加入到消息隊列,並當即開始執行,等待1.002s後輸出結果,當在最後一個延時函數加入隊列前循環加入1000個延時函數時, 最後一個延時函數是等待前面全部延時函數加入隊列後纔開始加入並執行,這個加入隊列的過程花費了一段時間,致使1.002s後第一個延時函數執行結果最早被輸出

這些示例雖然簡單,但能很好地幫助理解setTimeout延時的含義以及js的事件模型

相關文章
相關標籤/搜索