Browser and Node in the Event Loop

Foreword

js inherent non-blocking single-threaded scripting language. Language as a single thread, the main thread to perform only one task js code execution.
Non-blocking implementation relies on the event loop we want to talk about. eventloop specification is really bitter and difficult, just to understand, I do not recommend hard to chew.

Processes and threads

Js been saying is single-threaded language. So what is the thread of it, for most of the front-end students, it may not be so clear. Recommended Nguyen chiefs of this article, vivid
first of all, is the core of the computer CPU, it assumed all computing tasks. It's like a factory, always running.

process

Process like the factory floor, it represents a single CPU can handle the task.
At any one time, CPU always run a process, other processes is not running.
That is the smallest unit of resource allocation, an independent stack space and data storage space

Thread

Thread-like worker ratio in the workshop. Workshop space is shared by workers, symbolizing a process memory space is shared, each thread can use these shared memory.
That is the smallest unit of program execution, a process that can include multiple threads.

With respect to the process, the thread does not involve operational data space, so switching is more efficient and less overhead.

Js single-threaded origin

Obviously multiple processes in parallel processing to enhance the cpu utilization.
But as early js script appears, it should interact with the DOM, to complete the display to the user.
If multiple processes, simultaneous operation of DOM, then the consequences of not controllable.
For example: For the same button, different processes given a different color, in the end how the show.

As a scripting language, if you use multiple threads + lock, then too complicated, so js it is a single-threaded.

But with the development js, the ability to carry more and more limited to a single thread makes js efficiency and other restrictions may apply.
Thereby increasing the web worker to perform non-dom operation.

But the thread of non-main thread has some limitations, for example, can not manipulate the DOM, etc., that is, in order to ensure consistency of DOM manipulation, where they would not be a concern.

The main focus of the foundation of our ability or non-blocking, that is, the event loop.

Event loop browser

He said event loop will start with an event queue.
In the main thread runs, it produces heap (heap) and stack (stack).

Heap memory is object types of data we declared stack memory space is to run the basic data types and functions to perform.

The main thread reads from the task queue event, the process is constantly circulating, so this operation mechanism that is Event Loop.


For the synchronization code is executed directly.
Also different methods will be added when performing asynchronous event queue, but asynchronous event there is a difference, the difference lies in the implementation of priority.

Event Category

Because it is not the same between asynchronous tasks, so their execution priorities are different. Different asynchronous tasks are divided into two categories: micro-tasks (micro task) and macro task (macro task).

  • The following events were macro tasks:

setTimeout, setInterval, setImmediate,I/O, UI rendering

  • The following events were micro-tasks

Promise, Object.observe (obsolete), MutationObserver (html5 new features), process.nextTick

The execution stack code (synchronization tasks), always read the "Task Queue" (asynchronous task) executed before
immediately to handle all micro-tasks in the event queue when the current execution stack is finished, then go to the macro task queue remove an event. At the same event loop, micro-macro task is always executed prior to the task

For the execution order of tasks of different types as follows:

  1. Synchronization code execution
  2. event-loop start
  3. microTasks began to empty the queue (execution)
  4. Tasks check whether empty, there skip 4, no skip 6
  5. Tasks extracting a task from the queue, performing
  6. MicroTasks check whether empty, skip 2 if no skip 3
  7. The end of the event-loop

Probably flow chart is as follows:

As a direct see a chestnut:

setTimeout(function () {
    console.log(1);
});

new Promise(function(resolve,reject){
    console.log(2)
    resolve(3)
}).then(function(val){
    console.log(val);
})
// 2 3 1 
  1. Distinguish event types: macro task setTimeout, micro task .then
  2. 2 outputs a synchronization code execution
  3. Task Queue Empty micro output 3
  4. Macro task execution output 1

Following to a slightly more complex:

setTimeout(()=>{
    console.log('A');
},0);
var obj={
    func:function () {
        setTimeout(function () {
            console.log('B')
        },0);
        return new Promise(function (resolve) {
            console.log('C');
            resolve();
        })
    }
};
obj.func().then(function () {
    console.log('D')
});
console.log('E');
// c,e,d,b,a

You can try it yourself with examples.

In the event loop mechanism node

In the node, the event loop to show the state of the browser about the same. The difference is that the node will have its own model.
achieve node in the event loop is to rely on the libuv engine.
We know that node choose chrome v8 engine as js interpreter, v8 engine js code analysis api to call the corresponding node,
and these last api by libuv engine driver, perform the corresponding task, and the different events on different queue wait for the main thread.
So in fact the event loop node is present in libuv engine.

The node event is divided into the following major stages:

  • timers: this phase of implementation setTimeout () and setInterval () callback set.
  • I / O callbacks: perform almost all the callbacks, in addition to close the callback, timer callback, and setImmediate () callback.
  • idle, prepare: internal use only.
  • poll: get a new I / O event; node will be back up here under appropriate conditions, waiting for a new I / O.
  • check: After the pool phase, execution setImmediate () to set a callback.
  • close callbacks: the implementation of such socket.on ( 'close', ...) callback

poll phase

Worth the extra attention that poll stage

The stage has the following functions:

  1. Execution timer reaches the stage of the mission time limit.
  2. The implementation phase of the poll task queue.

If you enter the poll stage, and no task timer stage to join, the following will happen

  • 如果 poll 队列不为空的话,会执行 poll 队列直到清空或者系统回调数达到上限
  • 如果 poll 队列为空 ​ 如果设定了 setImmediate 回调,会直接跳到 check 阶段。 如果没有设定 setImmediate 回调,会阻塞住进程,并等待新的 poll 任务加入并立即执行。

process.nextTick()

nextTick 比较特殊,它有自己的队列,并且,独立于event loop。 它的执行也非常特殊,无论 event loop 处于何种阶段,都会在阶段结束的时候清空 nextTick 队列。

直接看例子吧:
process.nextTick

process.nextTick(function A() {
  console.log(1);
  process.nextTick(function B(){console.log(2);});
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)
// 1
// 2
// TIMEOUT FIRED

大概顺序如下:

  1. 因为nextTick的特殊性,当前阶段执行完毕,就执行。所以直接,输出1 2
  2. 执行到timer 输出 TIMEOUT FIRED

setImmediate

setImmediate(function A() {
  console.log(1);
  setImmediate(function B(){console.log(2);});
});

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

这个结果不固定,同一台机器测试结果也有两种:

// TIMEOUT FIRED =>1 =>2
或者
//  1=>TIMEOUT FIRED=>2
  1. 事件队列进入timer,性能好的 小于1ms,则不执行回调继续往下。若此时大于1ms, 则输出 TIMEOUT FIRED 就不输出步骤3了。
  2. poll阶段任务为空,存在setImmediate 直接进入setImmediate 输出1
  3. 然后再次到达timer 输出 TIMEOUT FIRED
  4. 再次进入check 阶段 输出 2

原因在于setTimeout 0 node 中至少为1ms,也就是取决于机器执行至timer时是否到了可执行的时机。

做个对比就比较清楚了:

setImmediate(function A() {
  console.log(1);
  setImmediate(function B(){console.log(2);});
});

setImmediate(function B(){console.log(4);});
setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 20);
// 1=>2=>TIMEOUT FIRED

此时间隔时间较长,timer阶段最后才会执行,所以会先执行两次check,出处1,2
下面再看个例子
poll阶段任务队列

var fs = require('fs')

fs.readFile('./yarn.lock', () => {
    setImmediate(() => {
        console.log('1')
        setImmediate(() => {
            console.log('2')
        })
    })
    setTimeout(() => {
        console.log('TIMEOUT FIRED')
    }, 0)
    
})
// 结果确定:
// 输出始终为1=>TIMEOUT FIRED=>2
  1. 读取文件,回调进入poll阶段
  2. 当前无任务队列,直接check 输出1 将setImmediate2加入事件队列
  3. 接着timer阶段,输出TIMEOUT FIRED
  4. 再次check阶段,输出2

小结

浏览器的事件循环
浏览器比较清晰一些,就是固定的流程,当前宏任务结束,就是执行所有微任务(不一定是全部,可能基于系统能力,会有所剩下),然后再下一个宏任务,微任务这样交替进行。
node中的事件循环
主要是把握不同阶段和特殊情况的处理,特别是poll阶段和 process.nextTick任务。

结束语

参考文章:

https://zhuanlan.zhihu.com/p/47152694
https://html.spec.whatwg.org/multipage/webappapis.html#event-loop
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
https://hackernoon.com/understanding-js-the-event-loop-959beae3ac40
https://juejin.im/post/5bac87b6f265da0a906f78d8
感谢上述参考文章,关于事件循环这里就总结完毕了,作为自己的一个学习心得。希望能帮助到有需求的同学,一起进步。

Guess you like

Origin www.cnblogs.com/pqjwyn/p/11238020.html