当前位置:网站首页>Browser event loop

Browser event loop

2022-06-26 20:03:00 Cat's jingle

Study JS,Event Loop It is a point that cannot be bypassed .JS The asynchronous execution logic of depends on Event Loop Mechanism , But this mechanism is defined in HTML Standard . because Event Loop Itself does not belong to ES Level of function , It is the hosting environment that provides this mechanism for scripts , So that the steps have the ability to execute asynchronously . according to JS Different hosting environments , It can be divided into browser event loop and node The event loop of , There are some differences between the two . Here we only talk about the browser event loop .
One 、 Why is there an event cycle

The browser will face many tasks at the same time , User interaction events ( mouse 、 keyboard )、 Network request 、 Page rendering, etc . And these tasks cannot be out of order , There must be a first come first served , The browser needs a predetermined set of logic to handle these tasks in an orderly manner , So the browser event loop was born , Again , Is a browser event loop , No javascript The event loop ,js Just a participant in the browser event loop .

Two 、 What is the event cycle

The browser divides the task area into Macro task and Micro task Or call it External tasks and Internal tasks , Internal tasks can be understood as js Internally processed tasks , External tasks can be considered as tasks handled by the browser .

External queue / Macro task queue (Task Queue) Callback

It can also be called macro task queue , The external event sources in the browser include the following :

dom operation ( Page rendering )、 User interaction ( mouse 、 keyboard )、 Network request (Ajax etc. )、History API operation (history.back、history.go…)、 Timer (setTimeout)
These external event sources can be many , In order to facilitate browser manufacturers to optimize ,HTML The standard clearly states that an event loop has one or more external queues , Each external event source has a corresponding external queue . Different time sources can have different priorities ( For example, between network time and user interaction , Browsers can prioritize mouse behavior , So as to make users feel more fluent ).

Internal queues / Micro task queue (Microtask Queue) Callback

It can also be called micro task queue , Refers to javascript The event queue inside the language , stay HTML In the standard , The event source of this queue is not specified , It is generally believed that there are the following :

Promise The success of the (.then) And failure (.catch)
MutationObserver
Object.observe( obsolete )
Except for the first one , The other two can be considered as not , In fact we js Only can be used in promise.
Every event cycle , Take one from the external task queue to execute , After an external task is executed, all internal tasks in the internal task queue are executed immediately ( Empty ), Then the browser performs a rendering , And then cycle again .
Here are two pieces of code
1.

//  What output will the following code get ?
console.log('1');
setTimeout(function() {
     
  console.log('2'); 
  Promise.resolve().then(function() {
    
		console.log('3'); 
  });
}, 0);
Promise.resolve().then(function() {
     
  console.log('4');
}).then(function() {
     
  console.log('5');
});
console.log('6');

// Execution order :164523

1. Due to the execution of the current js The code task is a macro task , So the first output is "1",
2. Continue to run into setTimeou, because setTimeout Is an external event source , Its internal code will be push To TaskQueue Wait for the next event loop to execute ,
3. When executed promise Of then or catche They will be appended to the end of this round of event loop in sequence ,
Continue to execute the output 6, Clear the tasks in the micro task queue after the macro task is completed , Then output 4、5
4. If any , After the rendering task , This event cycle ends
5. Start the next macro task , That's the first one setTimeout Code block in , Output 2, And then promise.then Add to the end of this cycle
6. Empty the micro task , Output 3

2.

  console.log(1)
  setTimeout(() => console.log(2), 200)
  setTimeout(() => {
    
    console.log(3)
    setTimeout(() => console.log(4), 50)
  }, 100)
  new Promise(resolve => {
    
    console.log(5)
    resolve()
    }).then(() => {
    
    console.log(6)
  })
  setTimeout(() => {
    
    new Promise(resolve => {
    
      console.log(7)
      resolve()
    }).then(() => {
    
      console.log(8)
    })
  })
  console.log(9)
// Execution order :159678342

1、 First , This code will be added to the macro task queue as a macro task . Now , The macro task queue has only one task , The main thread is empty , Perform this task .
2、console.log(1) Push , Print 1, completion of enforcement , Out of the stack
3、setTimeout Push , Hang up , wait for 200ms Then add the callback function to the macro task queue
4、setTimeout Push , Hang up , wait for 100ms Then add the callback function to the macro task queue
5、promise Push , Print 5, And then then Add to the micro task queue
6、setTimeout Push , Hang up , wait for 4ms Then add the callback function to the macro task queue . Here's a word ,HTML5 The standard stipulates setTimeout() The minimum value of the second parameter of ( Minimum interval ), Not less than 4 millisecond .
7、console.log(9) Push , Print 9, completion of enforcement , Out of the stack
8、 The main thread is empty , Check whether the micro task queue has functions , Found to have , Stack execution , Print 6
Come here , Don't consider other renderings , This event cycle ends , The print result is 1 5 9 6 .
The main thread is empty again , The event polling module will always poll the macro task queue for any tasks that can be executed . And obviously , In three pending setTimeout Inside , Step six setTimeout Is the fastest way to
The callback function is added to the macro task queue . At this time, the next event cycle can be carried out .
9、 Loop start , First, it will print 7, And then then Add to the micro task queue , Because there is nothing else to do in this cycle , Then execute the tasks in the micro task queue , Print 8
10、 Continue polling , And step four is faster than step three , Print first 3, I found again setTimeout, Continue to suspend
At this time, which of the tenth step and the third step is faster ? It is necessary to consider whether there are time-consuming tasks before step 3 to step 10 . We don't have any time-consuming tasks here , So step 10 is still better than
The third step is to execute . Print 4, Finally print 2 . The whole code is executed .

summary : The micro task queue will be emptied before the end of the current event cycle , The macro task will be executed only at the next event loop . Naturally, micro tasks take precedence over macro tasks . The priority here is only within an event cycle .

Here are some understandings about macro queues and micro queues

Every time you're ready to take out the first macro, before the task is executed , All the micro tasks have to be taken out one by one for execution , That is, the priority is higher than the macro task , And it has nothing to do with the code location of the micro task

setTimeout(()=>{
    
    console.log('0');
},0);
new Promise((resolve,reject)=>{
    
    console.log('1');
    resolve();
}).then(()=>{
    
    console.log('2');
    new Promise((resolve,reject)=>{
    
        console.log('3');
        resolve();
    }).then(()=>{
    
        console.log('4');
    }).then(()=>{
    
        console.log('5');
    })
}).then(()=>{
    
    console.log('6');
})
new Promise((resolve,reject)=>{
    
    console.log('7');
    resolve();
}).then(()=>{
    
    console.log('8');
})

Look at the synchronization , Look at the callback
The first timer , take 0 Push into macro queue
new Promise in executor Synchronous execution , Direct output 1
Then perform rresolve(), State change , call then(), Press the successful callback function into the micro queue (2)
Due to output 2 It hasn't been implemented yet , You can ignore what's under it new Promise, The first one at this time then() It's not finished yet, so the second then() It hasn't started yet
Then execute the next one new Promise, Direct will 7 Output , And then immediately resolve(), Changing the status will then() The successful callback is pushed into the micro queue (8)
At this point, the initialization code is completely executed

 Output :1 7
 Macro queue :[0]
 Micro queue :[2,8]

Execute the callback in the micro queue
Output 2,console.log(‘2’); After the execution new Promise, Direct output 3, Execute immediately resolve() After changing the State then() Successfully callback and press into the micro queue (4). Because of this time 4 Not yet implemented , Therefore, the following output 5 The callback of cannot be pushed into the micro queue , Instead, put it in the cache , Due to a change of state , The subsequent then() It's done , So put the outer layer next then The callback of is pushed into the micro queue (6)

 Output :1 7 2 3
 Macro queue :[0]
 Micro queue :[8,4,6]

Execution output 8, This step does not affect other operations , Then output 4, Push the subsequent callback into the micro queue (5)

 Output :1 7 2 3 8 4
 Macro queue :[0]
 Micro queue :[6,5]

The last is :

 Output :1 7 2 3 8 4 6 5 0
 Macro queue :[]
 Micro queue :[]
原网站

版权声明
本文为[Cat's jingle]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/177/202206261952131291.html