To understand asynchrony and synchronization in JS, you need to first understand the execution process of JS code and Event Loop.
Execution of JavaScript code
The operations that the program needs to perform will be put into the Call Stack (A LIFO (Last In, First Out) Stack), a first-in, last-out data structure.
const bar = () => console.log('bar')
const baz = () => console.log('baz')
const foo = () => {
console.log('foo')
bar()
baz()
}
foo()
When this code executes, foo() will be called first. Inside foo(), bar() is called first, then baz() is called. At this moment the Call Stack looks like this:
Each step of the operation is performed, and a new operation is pushed onto the top of the stack. After the execution is completed, it is popped from the top of the stack until the entire stack becomes Empty.
The function of the Event Loop is to go back each iteration to check whether there is an instruction to be executed in the Call Stack, and then execute it.
Asynchronous, synchronous in JavaScript
Execute code synchronously
In most cases, JavaScript executes code synchronously:
let log = console.log;
let a = 5;
let b = 50;
let a1 = function() { return 5 }
let b1 = function() { return 50 }
log(a1())
log(a2())
let a2 = function(num) { return 5*num }
let b2 = function() { return 50 }
log(a2(b2))
// 打印出:
// 5
// 50
// 250
code that executes asynchronously
setTimeout, callbacks, Promise, fetch, ajax, filesystem interaction, database calls, DOM event listener
In the above cases the code will be executed asynchronously.
The reason is that when the code executes these methods, it is uncertain how long the corresponding operation can be executed, so it will continue to execute downward.
Consider the following situation:
let a3 = 100;
setTimeout(function() { a3++ }, 0);
log(a3)
setTimeout(function() { log(a3) }, 0);
// 打印出
// 100
// 101
Synchronous code is put into the Call Stack for execution, and asynchronous code is put into a queue (Message Queue). The Event Loop will prioritize the tasks in the Call Stack. When the Call Stack is empty, it will take out the tasks in the Message Queue for execution.
ES6 Job Queue
ECMAScript 2015 introduced the concept of Job Queue, which is used by Promises. It makes the result of the asynchronous method execute as soon as possible, rather than at the end of the Call Stack.
Promises are a very nice implementation of async:
const bar = () => console.log('bar')
const baz = () => console.log('baz')
const foo = () => {
console.log('foo')
setTimeout(bar, 0)
new Promise((resolve, reject) =>
resolve('should be right after baz, before bar')
).then(resolve => console.log(resolve))
baz()
}
foo()
// foo
// baz
// should be right after baz, before bar
// bar
You can see that Promise will execute before setTimeout.
Take a look at this code, what is the execution order of it?
console.log(1);
setTimeout(() => console.log(2));
Promise.resolve().then(() => console.log(3));
Promise.resolve().then(() => setTimeout(() => console.log(4)));
Promise.resolve().then(() => console.log(5));
setTimeout(() => console.log(6));
console.log(7);
// 1
// 7
// 3
// 5
// 2
// 6
// 4
Nodejs Process.NextTick() and SetImmediate()
Process.NextTick() will be executed at the end of a cycle of the event loop. This method can be implemented to execute an asynchronous method as soon as possible instead of placing it in the asynchronous queue.
The Process.NextTick callback function will be added to the Process.NextTick queue, Promise.Then() will be added to the Promises Microtask Queue, and SetTimeout, SetImmediate will be added to the Macrotask Queue.
SetTimeout() The asynchronous delay of 0ms is very similar to SetImmediate(), they are both executed in the next event loop.
The event loop executes the Process.NextTick queue first, then the Promises microtask queue, then the macrotask queue.
console.log('script start');
// 异步
Promise.resolve().then(function() {
console.log('promise');
}).then(function() {
console.log('promise-then');
});
// 异步
setImmediate(function() {
console.log('setImmediate')
})
// 异步
setTimeout(function() {
console.log('setTimeout 0')
}, 0)
// 异步
setTimeout(function() {
return new Promise(resolve => {
console.log('setTimeout-delay 100ms promise')
resolve()
}).then(res => {
console.log('setTimeout-delay 100ms promise.then')
})
}, 100)
process.nextTick(function() {
console.log('process.nextTick')
})
console.log('script end');
/*
script start
script end
process.nextTick
promise
promise-then
setTimeout 0
setImmediate
setTimeout-delay 100ms promise
setTimeout-delay 100ms promise.then
*/
Reference link
https://nodejs.dev/en/learn/the-nodejs-event-loop/
The article was first published on IICCOM-Personal Blog | Technical Blog "Asynchronous and Synchronous in JavaScript"
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。