js event loop

Posted by radarhill on Fri, 11 Feb 2022 08:33:04 +0100

console.log('script start')
setTimeout(function(){
	console.log('setTimeout')
},0)

Promise.resolve()
.then(function(){
	console.log('promise1')
})
.then(function(){
	console.log('promise2')
})

console.log('script end')

Running results of the above code

script start
script end
promise1
promise2
setTimeput

Microsoft Edge, Firefox 40, iOS Safari and desktop Safari 8.0.8setTimeout were logged before and after promise1, promise2 - although this seems to be a competitive situation. This is really strange because Firefox 39 and Safari 8.0.7 are consistently correct

Why?
Each 'thread' has its own event loop, so each web worker has its own event loop, so it can be executed independently, and all windows of the same source can share the event loop, because they can communicate synchronously, and the event loop runs continuously to perform all queued tasks. The event loop has multiple task sources, which ensure the execution order in the source (for example, indexedDB regulates their execution order), but the browser can choose which source to execute the task in each loop. This allows browsers to prioritize performance sensitive tasks, such as user input

The task is planned so that the browser can enter the javascript/DOM field from within and ensure that these operations occur in an orderly manner. Between tasks, the browser can render updates. From mouse click to event callback, you need to schedule a task, just like parsing html. In the above example, the task also needs to schedule setTimeout

SetTimeout waits for a given delay and then schedules a new task for its callback. This is why setTimeout is performed after script end, because log script end is part of the first task, and setTimeout is recorded in a separate task

Microtasks usually schedule things that should happen after the current script is executed, such as reacting to batch actions, or making some asynchronous without taking a new task,. As long as there is no other JavaScript in the middle of execution, the micro task queue will be processed after the callback and at the end of each task. Any other micro tasks queued during the micro task are added to the end of the queue and processed. The micro task includes the mutation observer callback and Promise callback as shown in the above example

Once promise is solved or promise has been solved, he will discharge the micro task into its reactionary callback. This ensures that the promise callback is asynchronous even if the promise has been resolved. Therefore then(yey, nay) calling the resolved promise will immediately queue the micro task. This is why promsie1 and promis2 are after script end, because the currently running script must be completed before the micro task. promise1 and promsie2 record setTimeout before, because micro tasks always occur before the next task
View event loops, animated presentations

<div class="outer">
  <div class="inner"></div>
</div>

// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');

// Let's listen for attribute changes on the
// outer element
new MutationObserver(function () {
  console.log('mutate');
}).observe(outer, {
  attributes: true,
});

// Here's a click listener...
function onClick() {
  console.log('click');

  setTimeout(function () {
    console.log('timeout');
  }, 0);

  Promise.resolve().then(function () {
    console.log('promise');
  });

  outer.setAttribute('data-random', Math.random());
}

// ...which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);

Click inside 
click
promise
mutate
click
promise
mutate
timeout
timeout

external
click
promise
mutate
timeout

Topics: Javascript