This article is not guaranteed to be thorough, as it is inherently confusing, but tries to get to the point.

Compare the order of execution of the following

  • setTimeout
  • setInterval
  • setImmediate(NodeJS support,Browsers are not suitable for use)
  • new Promise(cb)promise.then(cb)(promisePromioseThe instance)
  • process.nextTick(nodejs)

There are some others.

  • MutaionObserver microTask(Browser)
  • socket.on('close', cb) close callback(nodejs)
  • fs.readFile I/O (nodejs)

classification

Synchronous execution

New Promise(CB) The CB code will execute synchronously, which is not really a consideration

MicroTask micro tasks

  • process.nextTick tickTask
  • promise.then(cb) microTask

Microtasks (on NodeJS) can be further divided into TickTasks and microtasks, both of which are microTask queues, and the same type of microtasks are executed first

The priority is tickTask > microTask

MacroTask macro task

  • setTimeout
  • setIntervalPriority withsetTimeoutThe timers are executed first who are pushed to the timers queue first
  • setImmediate

In the gap between different types of macro task switching, once there are tasks in the microtask queue, the microtask queue will be finished first, and then continue to execute the next type of macro task queue. In the same event loop, the microTask is always executed before the macroTask. If the macroTask is executed, the microTask will be executed in the next loop. And the microTask completes in this loop.

When entering timers, Check or other macro task queues, if there are no tasks in the microTask task queue, the system checks the microTask task queue after executing the preferentially executed macro task queue (Note: If a macroTask pushes a new microTask, it will still complete the task queue first and then execute the microTask first when switching to the next macroTask queue. It then enters the next type of macroTask queue (this process may be unfamiliar, but can be tested) and takes one execution from the macroTask queue at a time, then executes the microTask.

There is a nondeterministic case where the execution order of setImmediate and setTimeout is not fixed in NodeJS (according to the NodeJS developers).

For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process

As a test, the following execution is indeterminate and has no practical meaning

setTimeout((a)= > {
  console.log('1 setTimeout')
  setTimeout((a)= > {
    console.log('2 setTimeout')},0)
  setImmediate((a)= > {
    console.log('3 setImmediate')})},0)
setImmediate((a)= > {
  console.log('4 setImmediate')})Copy the code

nodejs

May 4setImmediate
1 setTimeout
3 setImmediate
2 setTimeout could also be 1setTimeout
4 setImmediate
3 setImmediate
2 setTimeout
Copy the code

setTimeoutThere is an invisible premise, and its second argument, which is the time to delay execution, is at least4msEven if 0 is specified, also note that it will not be executed until n ms, not n ms. Its execution time is uncertain, only that it will not be executed before n ms.

A setInterval callback with a while loop does not push an infinite number of callbacks into the Timers queue, even if the time is set to 0. Instead, it waits until this callback is completed before pushing the next callback into the Timers queue. Clearing the interval shows that the callback is executed only once, not many times.

The following example shows that setInterval pushes a callback to the Timers queue, executes it, and then pushes the next callback.

let count = 0
setTimeout((a)= > {
  console.log('1 setTimeout')},0)
const i = setInterval((a)= > {
  console.log('2 setInterval')
  count++
  if (count === 5) {
    clearInterval(i)
  }
  setTimeout((a)= > {
    console.log('3 setTimeout ', count)
  }, 0)},0)
setTimeout((a)= > {
  console.log('4 setTimeout')},0-1 setTimeout
2 setInterval
4 setTimeout
3 setTimeout  1
2 setInterval
3 setTimeout  2
2 setInterval
3 setTimeout  3
2 setInterval
3 setTimeout  4
2 setInterval
3 setTimeout  5
Copy the code

Nodejs event loop

┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ > │ timers │setTimeout setThe Interval │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ pending callbacks │ I/O in addition to other kinds of almost all │ callback └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ idle, Prepare internal use (ignore) │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ incoming: │ │ │ poll │ < ─ ─ ─ ─ ─ ┤ connections, │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ data, Etc. │ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ check │setImmediate │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ┤ close callbacks │ similar socket. On ('close',...). The close of the callback └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘Copy the code

These are basically macrotasks

setTimeout((a)= > {
  console.log('1 setTimeout')
  setTimeout((a)= > {
    console.log('2 setTimeout')},0)
  setImmediate((a)= > {
    console.log('3 setImmediate')
  })
  setTimeout((a)= > {
    console.log('4 setTimeout')},0)
  setImmediate((a)= > {
    console.log('5 setImmediate')})},0)
Copy the code

In the same event loop, the check queue executes and then the timers queue executes. (Check is not necessarily faster than timers)

1 setTimeout
3 setImmediate
5 setImmediate
2 setTimeout
4 setTimeout
Copy the code

If microTask tasks are pushed during check queue execution, let the current Check queue finish, then execute microTask, and then timers queue.

setTimeout((a)= > {
  console.log('1 setTimeout')
  setTimeout((a)= > {
    console.log('2 setTimeout')},0)
  setImmediate((a)= > {
    console.log('3 setImmediate')
    new Promise(res= > res()).then((a)= > {
      console.log('4 promise')
    })
    process.nextTick((a)= > {
      console.log('5 nextTick')
    })
  })
  setTimeout((a)= > {
    console.log('6 setTimeout')},0)
  setImmediate((a)= > {
    console.log('7 setImmediate')})},0)
Copy the code

As a result, the two setImmediate mediate sections are placed in the Check queue, where the setImmediate mediate section runs through the check queue and then through the next step, where The microTask executes.

1 setTimeout
3 setImmediate
7 setImmediate
5 nextTick
4 promise
2 setTimeout
6 setTimeout
Copy the code

Notice the difference between the code below and the code above

setTimeout((a)= > {
  console.log('1 setTimeout')
  setTimeout((a)= > {
    console.log('2 setTimeout')},0)
  setImmediate((a)= > {
    console.log('3 setImmediate')})new Promise(res= > res()).then((a)= > {
    console.log('4 promise')
  })
  process.nextTick((a)= > {
    console.log('5 nextTick')
  })
  setTimeout((a)= > {
    console.log('6 setTimeout')},0)
  setImmediate((a)= > {
    console.log('7 setImmediate')})},0-1 setTimeout
5 nextTick
4 promise
3 setImmediate
7 setImmediate
2 setTimeout
6 setTimeout
Copy the code

The title

Title 1

SetTimeout Does setInterval have the same priority? Whether they are pushed to the same queue

setTimeout((a)= > {
  console.log('1 timeout')},0)
setInterval((a)= > {
  console.log('2 interval')},0)
setTimeout((a)= > {
  console.log('3 timeout')},0)
setInterval((a)= > {
  console.log('4 interval')},0)
setTimeout((a)= > {
  console.log('5 timeout')},0)
Copy the code

Topic 2

setTimeout((a)= > {
  console.log('1 setTimeout')
  setTimeout((a)= > {
    console.log('2 setTimeout')},0)
  setImmediate((a)= > {
    console.log('3 setImmediate')
    setImmediate((a)= > {
      console.log('4 setImmediate')
    })
    process.nextTick((a)= > {
      console.log('5 nextTick')
    })
  })
  setImmediate((a)= > {
    console.log('7 setImmediate')
  })
  setTimeout((a)= > {
    console.log('8 setTimeout')},0)},0)

Copy the code

Go to give-me-job issue #1

conclusion

MicroTask is the master, macroTask must be allowed to microTask, but once let a type of macroTask to start execution, it must wait for this type of macroTask to complete, then can execute the microTask!! A macro task that is queued in a macro task cannot be executed until the next round, when no new macro task is available.


Welcome to my nuggets and public accounts, algorithms, TypeScript, React and their source ecology.