Home > Article > Web Front-end > Understand how asynchrony is handled in JavaScript
In website development, asynchronous events are a link that projects must deal with. Also because of the rise of front-end frameworks, SPA implemented through frameworks has become a standard for quickly building websites. Obtaining data has become an indispensable part; this article will talk about asynchronous processing in JavaScript.
First of all, of course, we must first understand what synchronization and asynchronous refer to respectively.
These two terms are always confusing for beginners. After all, the literal meaning in Chinese is easy to understand in reverse. From the perspective of information science, synchronization refers to Do things one by one, while asynchronously is when many things are processed together in parallel.
For example, when we go to the bank to handle business, queuing in front of the window is synchronous execution, and getting the number and doing other things first is asynchronous execution; through the characteristics of Event Loop, asynchronous events can be said in JavaScript It’s a piece of cake
So what is the way to handle asynchronous events in JavaScript?
The callback function we are most familiar with is the callback function. For example, the event listener registered when the web page interacts with the user needs to receive a callback function; or various functions of other Web APIs such as setTimeout
, xhr
can also be passed Pass the callback function to trigger at the time requested by the user. Let’s first look at an example of setTimeout
:
// callback function withCallback() { console.log('start') setTimeout(() => { console.log('callback func') }, 1000) console.log('done') }withCallback() // start // done // callback func
After setTimeout
is executed, when the specified time interval has passed, the callback function will be placed at the end of the queue , and then wait for the event loop to process it.
Note: Because of this mechanism, the time interval set by the developer to setTimeout
will not be exactly equal to the time elapsed from execution to triggering. Please be careful when using it. pay attention!
Although callback functions are very common in development, there are also many problems that are difficult to avoid. For example, because functions need to be passed to other functions, it is difficult for developers to control the processing logic in other functions; and because the callback function can only cooperate with try...catch
to catch errors, it is difficult to control when an asynchronous error occurs; in addition, There is the most famous "callback hell".
Fortunately, Promise appeared after ES6, saving developers who were trapped in hell. Its basic usage is also very simple:
function withPromise() { return new Promise(resolve => { console.log('promise func') resolve() }) } withPromise() .then(() => console.log('then 1')) .then(() => console.log('then 2')) // promise func // then 1 // then 2
What was not mentioned when discussing Event Loop before is that in the HTML 5 Web API standard, Event Loop adds a micro task queue, and Promise It is driven by the microtask queue; the triggering time of the microtask queue is when the stack is cleared. The JavaScript engine will first confirm whether there is anything in the microtask queue. If there is anything, it will be executed first and will not be taken from the queue until it is cleared. Pop new tasks onto the stack.
As in the above example, when the function returns a Promise, the JavaScript engine will put the function passed in later into the microtask queue, loop repeatedly, and output the results listed above. The subsequent .then
syntax will return a new Promise, and the parameter function will receive the result of the previous Promise.resolve
. With this function parameter transfer, developers can pipeline Handle asynchronous events sequentially.
If you add setTimeout
to the example, you can more clearly understand the difference between microtasks and general tasks:
function withPromise() { return new Promise(resolve => { console.log('promise func') resolve() }) } withPromise() .then(() => console.log('then 1')) .then(() => setTimeout(() => console.log('setTimeout'), 0)) .then(() => console.log('then 2')) // promise func // then 1 // then 2 -> 微任务优先执行 // setTimeout
In addition, the callback function mentioned above is difficult to handle Asynchronous errors can also be captured through the .catch
syntax.
function withPromise() { return new Promise(resolve => { console.log('promise func') resolve() }) } withPromise() .then(() => console.log('then 1')) .then(() => { throw new Error('error') }) .then(() => console.log('then 2')) .catch((err) => console.log('catch:', err)) // promise func // then 1 // catch: error // ...error call stack
Since the advent of ES6 Promise, asynchronous code has gradually changed from callback hell to elegant functional pipeline processing, but for those who are not familiar with it, For developers, it just changes from callback hell to Promise hell.
The new async
/await
is standardized in ES8. Although it is just syntactic sugar for combining Promise and Generator Function, it is passed through async
/await
Then asynchronous events can be processed with synchronous syntax, just like an old tree blooming new flowers. The writing style is completely different from Promise:
function wait(time, fn) { return new Promise(resolve => { setTimeout(() => { console.log('wait:', time) resolve(fn ? fn() : time) }, time) }) } await wait(500, () => console.log('bar')) console.log('foo') // wait: 500 // bar // foo
By setTimeout
is packaged into a Promise and then called with the await
keyword. You can see that the result will be synchronously executed first bar
and then foo
, that is, writing asynchronous events into synchronous processing mentioned at the beginning.
Look at another example:
async function withAsyncAwait() { for(let i = 0; i < 5; i++) { await wait(i*500, () => console.log(i)) } }await withAsyncAwait() // wait: 0 // 0 // wait: 500 // 1 // wait: 1000 // 2 // wait: 1500 // 3 // wait: 2000 // 4
The code implements the withAsyncAwait
function, using the for
loop and the await
keyword Execute the wait
function repeatedly; when executed here, the loop will wait for a different number of seconds in sequence before executing the next loop.
When using async
/await
, since the await
keyword can only be executed in async function, be sure to remember to use it at the same time .
In addition, when using loops to process asynchronous events, you need to note that many Array methods provided after ES6 do not support the async
/await
syntax. If you use forEach# here, ## Replace
for, the result will become synchronous execution, and numbers will be printed every 0.5 seconds:
Introduction to Programming! !
The above is the detailed content of Understand how asynchrony is handled in JavaScript. For more information, please follow other related articles on the PHP Chinese website!