首頁 > 軟體

一篇文章帶你瞭解vue.js的事件迴圈機制

2022-03-04 13:00:12

一、事件迴圈機制介紹       

JS是單執行緒的語言,瀏覽器和Node.js定義了各自的Event Loop(事件迴圈機制)則是用來解決非同步問題。將程式分為“主執行緒(執行棧)”與“Event Loop執行緒”,“主執行緒”自上而下依次執行同步任務,“Event Loop執行緒”將非同步任務推入宏任務佇列與微任務佇列去執行。

事件迴圈機制從整體上告訴了我們 JavaScript 程式碼的執行順序 Event Loop 即事件迴圈,是指瀏覽器或Node 的一種解決javaScript 單執行緒執行時不會阻塞的一種機制,也就是我們經常使用非同步的原理。“Event Loop執行緒”先執行宏任務佇列,然後執行微任務佇列,若微任務在執行過程中產生了新的微任務,則繼續執行微任務,微任務執行完畢後,再回到宏任務中進行下一輪迴圈。即繼續先執行宏任務佇列,再執行 微任務佇列。

宏任務:

script(整體程式碼)/setTimeout/setInterval/setImmediate/ I/O / UI Rendering

微任務:

process.nextTick()/Promise/Async、Await(實際就是Promise)/MutationObserver(html5新特性)

setTimeout 和 setInterval 等都是任務源,真正進入任務佇列的是他們分發的任務。

優先順序

setTimeout = setInterval 一個佇列setTimeout > setImmediate process.nextTick > Promise

二、經典事件迴圈面試題

1.在下面這段程式碼是面試中關於這類問題的經典考題,其中包含了同步、非同步任務,幾個輸出的先後順序是怎樣的。

setTimeout(function(){
    console.log('1')
});
new Promise(function(resolve){
    console.log('2');
    resolve();
}).then(function(){
    console.log('3')
});
console.log('4');
// 2,4,3,1

首先進行任務劃分,同步任務:new Promise()console.log('4')宏任務setTimeout()微任務Promise().then()Event Loop依次將同步任務推入執行棧並執行,當遇到宏任務或微任務時,推到宏任務或微任務佇列中。先執行同步任務,同步佇列執行完畢,會去微佇列取任務,直到微佇列清空,再去宏佇列取任務執行。故此段程式執行順序為:

new Promise()console.log('4')Promise().then()setTimeout()

 2.範例2

 答案輸出為:async2 end => Promise => async1 end => promise1 => promise2 => setTimeout

3.範例3

        mounted(){
            this.test();
 
        },
        methods:{
            test(){
                console.log('script start');
 
                this.async1();
 
                setTimeout(function() {
                 console.log('setTimeout')
                }, 0);
 
                new Promise(resolve => {
                    console.log('Promise')
                    resolve()
                })
                .then(function() {
                console.log('promise1')
                })
                .then(function() {
                console.log('promise2')
                })
 
                console.log('script end')
            },
            async async1() {
                await this.async2()
                    console.log('async1 end')
            },
            async async2() {
              console.log('async2 end')
            },
        }

新版的chrome瀏覽器中不是如上列印的,因為chrome優化了,await變得更快了,輸出為:

// script start => async2 end => Promise => script end => async1 end => promise1 => promise2

分析這段程式碼:

  • 執行程式碼,輸出script start。
  • 執行async1(),會呼叫async2(),然後輸出async2 end,此時將會保留async1函數的上下文,然後跳出async1函數。
  • 遇到setTimeout,產生一個宏任務
  • 執行Promise,輸出Promise。遇到then,產生第一個微任務
  • 繼續執行程式碼,輸出script end
  • 程式碼邏輯執行完畢(當前宏任務執行完畢),開始執行當前宏任務產生的微任務佇列,輸出promise1,該微任務遇到then,產生一個新的微任務 
  • 執行產生的微任務,輸出promise2,當前微任務佇列執行完畢。執行權回到async1 
  • 執行await,實際上會產生一個promise返回,即
  • let promise_ = new Promise((resolve,reject){ resolve(undefined)})
  • 執行完成,執行await後面的語句,輸出async1 end 最後,執行下一個宏任務,即執行setTimeout,輸出setTimeout
  • 注意以上分析是舊版瀏覽器await執行慢導致async1在微任務執行後執行。

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!


IT145.com E-mail:sddin#qq.com