JS Asynchronous-Advanced
- The JS asynchronization explained earlier is in the first-order application
- This chapter focuses on the principles and advances of JS asynchronization
- A little difficult for beginners, try to be as deep as possible
Main Contents of this Chapter
- event loop
- promise Advancement
- async/await
- Micro/Macro Tasks
Interview Questions Related to this Chapter
- Describe the mechanism of event loop (event loop/event polling), which can be graphed
- What are macro tasks and micro tasks, and what is the difference between them?
- What are the three states of Promise?How to change
Scene Title
The connection between promise the N and catch
//Topic 1 Promise.resolve().then(() => { console.info(1) }).catch(() => { console.info(2) }).then(() => { console.info(3) }) //Output: 1 3 //Question 2 Promise.resolve().then(() => { console.info(1) throw new Error('error1') }).catch(() => { console.info(2) }).then(() => { console.info(3) }) //Output: 1 2 3 //Question 3 Promise.resolve().then(() => { console.info(1) throw new Error('error1') }).catch(() => { console.info(2) }).catch(() => { //Here is catch console.info(3) }) //Output: 1 2
async/await syntax
async function fn() { return 100 } (async function () { const a = fn() // ?? const b = await fn() // ?? })() (async function () { console.info('start') const a = await 100 console.info('a', a) const b = await Promise.resolve(200) console.info('b', b) const c = await Promise.reject(300) console.info('c', c) console.info('end') })()//Execute, print out those
Order of promise and setTimeout
console.info(100) setTimeout(() => { console.info(200) }) Promise.resolve().then(() => { console.info(300) }) console.info(400)
Additional async/await sequencing issues
async function async1 () { console.info('async1 start') await async2() console.info('async1 end') } async function async2 () { console.info('async2') } console.info('script start') setTimeout(function () { console.info('setTimeout') }, 0) async1() new Promise(function (resolve) { console.info('promise1') resolve() }).then(function () { console.info('promise2') }) console.info('script end')
Event loop (event loop/event polling)
- JS is single-threaded
- Asynchronization is based on callbacks
- event loop is the implementation principle of asynchronous callback
How does JS execute?
- From front to back, line by line
- Stop execution of the following code if a line fails to execute
- Execute synchronous code before asynchronous
console.info('Hi') setTimeout(function cb1() { console.info('cb1') //cb is callback }, 5000) console.info('Bye')
Start explaining the event loop process
- Beginners may find it difficult to go as far as possible
- The first time you explain, don't stop what you don't understand, you will repeat it three times
- Don't skim over details, don't expand scope, the core is the event loop process
Summarize event loop process 1
- Synchronize code, line by line in Call Stack
- Encountered asynchronous, will first "record" the opportunity to wait (timer, network requests, etc.)
- When it's time, move to Callback Queue
Summarize event loop process 2
- Event Loop starts working if Call Stack is empty (that is, when synchronization code is executed)
- Polling Find Callback Queue, Move to Call Stack if necessary to execute
- Then continue polling (like a perpetual machine)
DOM events and event loop
- JS is single threaded
- Asynchronous (setTimeout, ajax, etc.) uses callbacks, based on event loop
- DOM events also use callbacks, based on event loop
console.info('Hi') setTimeout(function cb1() { console.info('cb1') //cb is callback }, 5000) console.info('Bye')
<button id="btn1"></button> <script> console.info('Hi') $('btn1').click(function (e) { console.info('button clicked') }) console.info('Bye') </script>
Promise
- Three states:
- pending,resolved,rejected
- Pending -> resolved or pending -> rejected
- Change is irreversible
- The representation and change of state
- pending state, does not trigger the then and catch
- resolved state, triggering subsequent then callback functions
- rejected state, triggering subsequent catch callback functions
- The effect of the then and catch on the state
The N and catch change state
- The n returns resolved normally, rejected if there is an error in it
- catch returns resolved normally, rejected if there is an error
const p1 = Promise.resolve().then(() => { return 10 }) console.info('p1', p1) //resolved triggers subsequent then callbacks p1.then(() => { console.info('123') }) const p2 = Promise.resolve().then(() => { throw new Error('then error') }) console.info('p2', p2) //reject triggers subsequent catch callbacks p2.then(() => { console.info('456') }).catch(err => { consoel.info('err100', err) })
Promise Summary
- Three states, state representation and change
- The effect of the then and catch on the state (important)
- Chained calls to the then and catch (common reference)
async/await
- Asynchronous callback hell
- Promise then catch chain call, but also based on callback functions
- async/await is synchronous syntax, eliminating callback functions completely
Relationship between async/await and Proise
-
async/await is the ultimate weapon to eliminate asynchronous callbacks
-
But they are not mutually exclusive with Proise
-
Instead, they complement each other
-
Execute the async function and return a Promise object
-
await is equivalent to Promise's then
-
try...catch catches exceptions instead of Promise's catch
async function fn1() { //return 100 return Promise.resolve(200) } const res1 = fn1() //Executing the async function returns a promise object console.info('res1', res1) //promise object res1.then(data => { console.info('data', data) //200 }) !(async function () { const p1 = Promise.resolve(300) const data = await p1 //await is equivalent to Promise's then console.info('data', data) })
The nature of asynchronism
- async/await is the ultimate weapon to eliminate asynchronous callbacks
- JS or single threaded, asynchronous, event loop based
- async/await is just a grammatical sugar, but it is delicious!
async function async1 () { console.info('async1 start') //2 Important await async2() //undefined //Behind await, you can think of it as something in the callback.That is, asynchronous //Similar, event loop, settim(cb1) //setTimeout(function() {console.info('async1 end') }) //Promise.resolve().then(() => {console.info('async1 end')}) console.info('async1 end') //5 } async function async2 () { console.info('async2') //3 Important } console.info('script start') //1 async1() console.info('script end') //4 //The synchronization code has been executed (event loop)
for ... of
- For... In (and forEach for) is a regular synchronous traversal
- For... Of is often used for asynchronous traversal
function muti(num) { return new Promise(resolve => { setTimeout(() => { resolve(num * num) }, 1000) }) } const nums = [1, 2, 3] nums.forEach(async (i) => { const res = asait muti(i) console.info(res) //Simultaneous printing after 1 second: 1, 4, 9 }) !(async function () { for (let i of nums) { const res = await muti(i) console.info(res) //Output every second: 1, 4, 9 } })()
Summary of async/await
- async/await resolves asynchronous callbacks and is a nice grammatical sugar
- The relationship between async/await and Proise is important!
- Use of for...of
Macro Task and Micro Task
- What is a macro task and what is a micro task
- Macro Tasks: setTimeout, setInterval, Ajax, DOM Events
- Microtask: Promise async/await
- Micro tasks execute earlier than macro tasks (remember first)
- event loop and DOM rendering
- Differences between micro and macro tasks
console.info(100) //1 setTimeout(() => { console.info(200) //4 }) Promise.resolve().then(() => { console.info(300) //3 }) console.info(400) //2
event loop and DOM rendering
- Return to the process of event loop s again
- JS is single-threaded and shares a thread with DOM rendering
- When the JS executes, you have to leave some time for the DOM to render
const $p1 = $('<p>A piece of text</p>') const $p2 = $('<p>A piece of text</p>') const $p3 = $('<p>A piece of text</p>') $('#container').append($p1).append($p2).append($p3) console.info('length', $('#container').children().length) alert('This time call stack End, DOM Structure updated, but rendering has not been triggered') //(alert blocks js execution and DOM rendering for easy viewing)
Review the event loop process (increasing DOM rendering timing)
event loop and DOM rendering
- Each Call Stack is emptied (i.e. the end of each poll), i.e. the synchronization task is completed
- All opportunities for DOM re-rendering, DOM structure re-rendering if changed
- Then trigger the next event loop again
Differences between micro and macro tasks
- Macro Task: Triggered after DOM rendering, such as setTimeout
- Microtask: triggered before DOM rendering, such as Promise
- Demonstrate the phenomenon before investigating the principles
const $p1 = $('<p>A piece of text</p>') const $p2 = $('<p>A piece of text</p>') const $p3 = $('<p>A piece of text</p>') $('#container').append($p1).append($p2).append($p3) //Microtask: triggered before DOM rendering Promise.resolve().then(() => { console.info('length1', $('#container').children().length) alert('Promise then') //Does DOM render?NO }) setTimeout(() => { console.info('length2', $('#container').children().length) //3 alert('setTimeout') //Does DOM render?yes })
Explain from event loop why microtasks execute earlier
Why?
- Microtasks are specified in ES6 syntax
- Macro tasks are specified by the browser
Micro and Macro Tasks - Summary
- What are the macro tasks?What are microtasks?Microtask triggers earlier
- Relationship between Micro Tasks, Macro Tasks and DOM Rendering
- Micro Tasks, Macro Tasks, and DOM Rendering, in the event looop process
async function fn() { return 100 } (async function () { const a = fn() // ?? const b = await fn() // ?? })() (async function () { console.info('start') const a = await 100 console.info('a', a) const b = await Promise.resolve(200) console.info('b', b) const c = await Promise.reject(300) console.info('c', c) console.info('end') })()
Order of promise and setTimeout
console.info(100) setTimeout(() => { console.info(200) }) Promise.resolve().then(() => { console.info(300) }) console.info(400)
Additional async/await sequencing issues
async function async1 () { console.info('async1 start') await async2() console.info('async1 end') } async function async2 () { console.info('async2') } console.info('script start') setTimeout(function () { console.info('setTimeout') }, 0) //Connect the left code and read it together async1() new Promise (function (resolve) { console.info('promise1') resolve() }).then(function () { console.info('promise2') }) console.info('script end')