Skip to content

Commit

Permalink
lgc-mergeThree
Browse files Browse the repository at this point in the history
  • Loading branch information
amandakelake committed Apr 22, 2018
1 parent 47897e1 commit 04cdf75
Show file tree
Hide file tree
Showing 2 changed files with 415 additions and 0 deletions.
201 changes: 201 additions & 0 deletions Browser/browser-en.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,204 @@

#### Event loop

As we all know, JS is a non-blocking and single-threaded language, because JS was born to interact with the browser in the beginning. If JS is a multi-threaded language, we may have problems handling DOM in multiple threads (imagine adding nodes in a thread and deleting nodes in another thread in the same time), certainly, we can introduce a read-write lock to solve this problem.

Execution context, generated during JS execution, will be pushed into call stack sequentially. Asynchronous codes encountered will be handed up and pushed into the Task queues (there are multiple tasks). Once the call stack is empty, the Event Loop will take out the codes that need to be executed from the Task queue and push it into the execution of the call stack, thus essentially speaking that the asynchronous behavior in JS is actually synchronous.

```js
console.log('script start');

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

console.log('script end');
```

The above code is asynchronous, even though the `setTimeout` delay is 0. That’s because the HTML5 standard stipulates that the second parameter of the function `setTimeout` must not be less than 4 milliseconds, or it will increase automatically. So `setTimeout` is still logged after `script end`.

Different task sources are assigned to different Task queues. Task sources can be divided into `microtasks` and `macrotasks`. In the ES6 specification, `microtask` is called `jobs` and `macrotask` is called `task`.

```js
console.log('script start');

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

new Promise((resolve) => {
console.log('Promise')
resolve()
}).then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});

console.log('script end');
// script start => Promise => script end => promise1 => promise2 => setTimeout
```

Although `setTimeout` is set before `Promise`, the above printing still occurs because of that `Promise` belongs to microtask and `setTimeout` belongs to macrotask

Microtasks include `process.nextTick`, `promise`, `Object.observe`, `MutationObserver`

Macrotasks include `script``setTimeout``setInterval``setImmediate``I/O``UI rendering`

Many people have a wrong misunderstanding that microtasks are faster than macrotasks. Because the macrotask includes `script`, the browser will perform a macrotask first, followed by microtasks if there is asynchronous code.

So the correct sequence of an event loop is like this:

1、Execute synchronous codes, which belongs to macrotask
2、Once call stack is empty, query if any microtasks need to be executed
3、Execute all the microtasks
4、If necessary, render the UI
5、Then start the next round of the Event loop, and execute the asynchronous codes in the macrotask

According to the above sequence of the Event loop, if the asynchronous codes in the macro task have a large number of calculations and need to operate the DOM, we can put the operation DOM into the microtask for faster interface response.

##### Node 中的 Event loop

The Event loop in Node is not the same as in the browser.

The Event loop in Node is divided into 6 phases, and they will be executed in sequence.

```
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<──connections─── │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
```

###### timer

The `timer` phase executes the callbacks of `setTimeout` and `setInterval`

`Timer` specifies the time that callbacks will run as early as they can be scheduled after the specified amount of time has passed rather than the exact time a person wants it to be executed.

The lower limit time has a range: `[1, 2147483647]`, if the set time is not in this range, it will be set to 1.

###### I/O

The `I/O` phase executes the callbacks of timers and `setImmediate`, besides that for the close event

###### idle, prepare

The `idle, prepare` phase is for internal implementation

###### poll

The `poll` phase has two main functions:

1. Executing scripts for timers whose threshold has elapsed, then
2. Processing events in the poll queue.

When the event loop enters the `poll` phase and there are no timers scheduled, one of two things will happen:

* If the `poll` queue is not empty, the event loop will iterate through its queue of callbacks executing them synchronously until either the queue has been exhausted, or the system-dependent hard limit is reached.

* If the `poll` queue is empty, one of two more things will happen:
1. If scripts have been scheduled by `setImmediate`. the event loop will end the `poll` phase and continue to the check phase to execute those scheduled scripts.
2. If scripts have not been scheduled by `setImmediate`, the event loop will wait for callbacks to be added to the queue, then execute them immediately.

Once the `poll` queue is empty the event loop will check for timers whose time thresholds have been reached. If one or more timers are ready, the event loop will wrap back to the timers phase to execute those timers' callbacks.

###### check

The `check` phase executes the callbacks of `setImmediate`

###### close callbacks

The `close` event will be emitted in this phase.
And in Node, the order of execution of timers is random in some cases

```js
setTimeout(() => {
console.log('setTimeout');
}, 0);
setImmediate(() => {
console.log('setImmediate');
})
// Here, it may log setTimeout => setImmediate
// It is also possible to log the opposite result, which depends on performance
// Because it may take less than 1 millisecond to enter the event loop, `setImmediate` would be executed at this time.
// Otherwise it will execute `setTimeout`
```

Certainly, in this case, the execution order is the same

```js
var fs = require('fs')

fs.readFile(__filename, () => {
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
});
// Because the callback of `readFile` was executed in `poll` phase
// Founding `setImmediate`,it immediately jumps to the `check` phase to execute the callback
// and then goes to the `timer` phase to execute `setTimeout`
// so the above output must be `setImmediate` => `setTimeout`
```

The above is the implementation of the macrotask. The microtask will be executed immediately after each phase is completed.

```js
setTimeout(()=>{
console.log('timer1')

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

setTimeout(()=>{
console.log('timer2')

Promise.resolve().then(function() {
console.log('promise2')
})
}, 0)
// The log result is different, when the above code is executed in browser and node
// In browser, it will log: timer1 => promise1 => timer2 => promise2
// In node, it will log: timer1 => timer2 => promise1 => promise2
```

`process.nextTick` in Node will be executed before other microtasks.

```js
setTimeout(() => {
console.log("timer1");

Promise.resolve().then(function() {
console.log("promise1");
});
}, 0);

process.nextTick(() => {
console.log("nextTick");
});
// nextTick => timer1 => promise1
```


#### Storage

##### cookie,localStorage,sessionStorage,indexDB
Expand Down
Loading

0 comments on commit 04cdf75

Please sign in to comment.