Macro and micro tasks

Refer to the article

Refer to the article

Why is JS single threaded?

  • The single thread of JavaScript, relative to its purpose.

  • As a browser scripting language, JavaScript’s primary purpose is to interact with users and manipulate the DOM.

  • If JS is not single threaded, this can lead to complex synchronization issues

    • For example, suppose that JavaScript has two threads at the same time

    • When one thread adds content to a DOM node and another thread removes it, which thread should the browser use?

  • To avoid complexity, JavaScript has been single-threaded since its inception, and this has been a core feature of the language and will not change.

Task queue

  • Single-threaded means that all tasks need to be queued and executed in order.

  • But as a scripting language, two important things that language designers need to consider when running are real-time execution and efficiency.

    • Real-time performance refers to the effectiveness of code execution in the process of code execution and whether the current execution task plays a role under the current effectiveness.
    • Efficiency, in this case, is the rate of delay per statement during code execution resulting in subsequent execution.
  • There are two types of tasks, synchronous and asynchronous.

    Synchronization task
    • Tasks queued for execution on the main thread can be executed only after the previous task is executed.

    • When a function returns, the caller gets the expected result (that is, gets the expected return value or sees the expected effect), the function is synchronous.

    • console.log('Hello');
      Copy the code
    Asynchronous tasks
    • Tasks that do not enter the main thread but enter the task queue.
    • An asynchronous task is executed on the main thread only when the “task queue” notifies the main thread that it is ready to execute.
    • A function is asynchronous if the caller does not get the expected result when it returns, but needs to get it in the future by some means.
  • When an event is triggered and there is a single-thread linear execution, it is not only possible that other tasks are being executed in the thread, preventing the current event from being executed immediately, but more likely that the execution efficiency is affected by the thread blocking caused by the direct execution of the current event.

  • In this case, event-triggered execution processes, such as functions, enter the callback process, and the browser provides a message queue for the implementation of different callbacks.

  • When the main context content is executed, the callback logic in the message queue is extracted and executed. This is the simplest model of the event mechanism.

  • The browser’s event callback is an asynchronous callback mechanism.

    • One is represented by setTimeout timer, which directly enters the event queue to wait for execution after it is triggered.
    • One is XMLHTTPRequest, which triggers the call to be executed by another thread and then wraps the return value into an event queue to wait.

Macro task and micro task

What is the (macro) task?

  • Any JavaScript code that is scheduled to execute by a standard mechanism is a task
  • Executing a program, executing an event callback, or firing interval/timeout are all scheduled on the task queue.
  • Common macro tasks
    • Including the entire code script, setTimeout, setInterval, setImmediate

What are microtasks?

  • When a task exists, the event loop checks to see if the task is ceding control to other JavaScript code.
  • If not executed, the event loop runs all of the microtasks in the microtask queue.
  • The microtask loop is then processed multiple times in each iteration of the event loop, including after the event and other callbacks are processed.
  • Second, if a microtask adds more microtasks to the queue by calling queueMicrotask(), those newly added microtasks will run before the next task.
  • The microtask must be executed asynchronously, after the main function is executed, after the function created by the microtask is executed, and before the current macro task ends.
  • Common microtasks

Execute the process

  • The entire script script begins execution as a macro task

  • When a microtask is encountered, it is pushed to the microtask queue, and a macro task is pushed to the macro task queue

  • After the macro task is executed, check whether any microtask can be executed

  • If any executable microtasks are found, all the microtasks are executed

  • When the macro task completes, the render is checked, and the GUI thread takes over

  • After rendering, the JS thread takes over, starting new macro tasks, and does so again and again until all tasks are completed

In actual four.

one
  • console.log('global') for (var i = 1; i <= 5; i ++) { setTimeout(function() { console.log(i) },i*1000) console.log(i) } new Promise(function (resolve) { console.log('promise1') resolve() }).then(function () { console.log('then1') }) setTimeout(function () { console.log('timeout2') new Promise(function (resolve) { console.log('timeout2_promise') resolve() }).then(function () {  console.log('timeout2_then') }) }, 1000)Copy the code
  • // When the synchronization task console is encountered, execute directly, print 'global' // for loop through five times, Trigger a timeout macro task and a synchronization task console each time, // push the macro task triggered by each iteration into the macro task queue, synchronize the task console, directly execute, print I // at this time, the macro task queue has 5 timeout macro tasks // the console prints 'global' in sequence, Console. log('promise1') Print 'promise1' // push microtask promise. then to microtask queue // console print 'global', 1,2,3,4,5, 'promise1' // encounter Timeout, trigger macro task, // When the first macro task, i.e. the whole script, is about to finish, check the microtask queue // There is Promise. Then in the microtask queue, execute it, print 'then1' // The console after the first macro task is finished: 'global', 1,2,3,4,5, 'promise1', 'then1' // execute the second macro task // execute the first macro task Timeout generated by the for loop, print '6', then the microtask queue is empty, execute the next macro task // note, Since the next four macro tasks in the macro task queue will fire after 6 seconds // and the fifth macro task will fire after 1 second, the browser will execute the fifth macro task first. Log ('timeout2') and console.log(' timeout2_PROMISE ') // Prints 'timeout2' in order, 'timeout2_PROMISE' // triggers the microtask promise. then, pushing it to the microtask queue. // the console prints 'global', 1,2,3,4,5, 'promise1', 'then1', 'timeout2', 'timeout2_promise' // then perform the remaining four macro tasks in sequence Timeout // finally console prints 'global', 1,2,3,4,5, 'promise1', 'then1', 'timeout2', 'Timeout2_PROMISE', 6, 6, 6Copy the code
two
  • function taskOne() { console.log('task one ... ') setTimeout(() => { Promise.resolve().then(() => { console.log('task one micro in macro ... ') }) setTimeout(() => { console.log('task one macro ... ') }, 0) }, 0) taskTwo() } function taskTwo() { console.log('task two ... ') Promise.resolve().then(() => { setTimeout(() => { console.log('task two macro in micro... ') }, 0) }) setTimeout(() => { console.log('task two macro ... ') }, 0) } setTimeout(() => { console.log('running macro ... ') }, 0) taskOne() Promise.resolve().then(() => { console.log('running micro ... ')})Copy the code
  • // The global context is pushed into the call stack. // The global context is pushed into the call stack. // The global context is pushed into the call stackCopy the code
  • task one ...
    task two ...
    running micro ...
    running macro ...
    task one micro in macro ...
    task two macro ...
    task two macro in micro...
    task one macro ...
    Copy the code