Special instructions

  • This blog post is minepersonalrightJavaScript Asynchronous OperationsSummarize classified.
  • Through this article I also hope that readers can learn fromThe macro“Looks at how JavaScript asynchronous operations have evolved.
  • But if you want to learn all about it in this blog postpromiseorasyncAll the knowledge of functions and other technologies is not realistic.
  • It is recommended that you read Nguyen Yifeng’s Introduction to ECMAScript 6 – Promise Objects in detail, as well as Chapter 11 of Nicholas’ Deep Understanding of ES6 (Page 219).

Abstract

To put it in a slightly philosophical way: the ultimate goal of the evolution of JavaScript asynchronous operations is to make asynchronous code look more like synchronous code. The single-threaded nature of the JS language, rather than making it look bad to those who use it, has led programmers to create all sorts of tools to improve its performance. From callback functions to Promise objects, to the async function that is supposed to be the ultimate solution for JS asynchronous operations. Each of these evolved from scratch, from communities to standards. This blog post will start at the source and discuss why JS needs asynchronous operations. Then explain some conceptual terms. Finally, let's take a look at the development of asynchronous JS operations.

keywords

Synchronous | Asynchronous | Event Loop | CallBack | Promise | Generator | Async/Await

Why does JavaScript need asynchronous operations

Single thread

  • The JavaScript language was originally designed to solve the problem of user interaction with the browser.
  • And one of the big things isDOM manipulation. Imagine that a block of code is inModify the DOMThere is another code block requiredDelete the DOM. So who should you listen to?
  • To avoid more complex thread synchronization issues, only one thread is responsible for executing code in the JS execution environment. This is often referred to as single-threaded JavaScript working mode.

Working mode

  • Sometimes when you’re doing something that takes a lot of time, you have to wait for the current task to finish before moving on to the next one. This will cause the program to appear suspended animation, also known as blocking.
  • To avoid this, JS divides working modes into two main categories: synchronous mode and asynchronous mode.

Some of the concepts

Synchronous

The code executed in synchronous mode will be in
Execution stackIn queue execution. That’s what we call it
Pressure stack operationAnd when it’s finished, it’s going to be
Pop up the stack.
The closure functionYou can take a variable
persistedIn the execution stack.

Asynchronous

Asynchronous mode code
Will not enter the main thread, which is our execution stack. But to
Task queueOr,
The message queueIn the. when
Execution stackAll of the
Synchronization taskOnce executed, the system will read it
Task queue, those
Asynchronous codeWill end the wait,
Entering the execution stack, start executing.

Note: Synchronous or asynchronous means that the API provided by the runtime environment works in synchronous or asynchronous mode.

Synchronous API: console.log() Asynchronous API: setTimeout ()

Stack

The execution stack. As the main thread runs, it generates the heap and the stack, and the code in the stack calls various external APIs that add events to the task queue.

Message queue

Message queue.

Web API

Various APIs provided by the browser.

Event loop

As long as
The stackThe code in the
The main threadfrom
The message queueThis process is cyclic, so the whole operation mechanism is also called
Event loop
Event Loop.

For the relationship between Stack, Message Queue, Event Loop and Web API, please refer to the following diagram:

Evolutionary history

CallBack

The callback functionIs the earliest implementation of asynchronous operations. It is made of
Caller definitionAnd gave them to
Executor executionThe function. Some common applications are:
Event mechanismand
Publish-subscribe modelAnd so on.

var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = function () { ... } // The callback function Xhr. onError = function () {// The callback function Xhr. onError = function () {... } // The callback function xhr.send() that triggers when a request is sent in error.

The bug: There are special tricks to be used when sending multiple requests and trying to do something with the results of all those requests when they all return successful. The simplest way to do this is to nest each request and execute the next request when one succeeds. The problem with this implementation is first of all a waste of time, and second it creates what we often call callback hell, making the code both ugly and difficult to maintain.

$. Ajax ({url: URL1, /* callback1 */ success: function () {/* $. Ajax ({url: URL1, /* callback1 */ success: function ()) {/* $. Ajax ({url: URL1, /* callback1 */ success: function ()) {/* $. Ajax (); URL2, /* callback2 */ success: function () { ... $. Ajax ({... })}})})

Promise

Promise is a
object, it is for
Asynchronous operations
The results ofPrepared by the
A placeholder. Used to represent
Asynchronous tasksAt the end of the day
successfulor
failure. The Promise
stateAnd once that’s done, it’s
It cannot be modified.

  • The life cycle of Promise: in the implementationAsynchronous operationswhencommitmentI’m going to give you a result, and I’m going to give you a result before I give you a resultpendingThe state, which gives you two outcomes, is successfulfulfilledState and failurerejectedState. After the result is given, some reaction needs to be madetask), which is the opposite ofonFulfilledonRejected.

  • Then () method: You can use the then() method to perform specific actions when a Promise’s state changes.

    The essence of a Promise is use
    The callback functiondefine
    Asynchronous tasksTasks to perform after completion.

    function ajax (url) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest() xhr.responseType = 'json' xhr.onload = function () { if (this.status === 200) {  resolve(this.response) } else { reject(new Error(this.statusText)) } } xhr.send() }) } ajax('/api/user.json').then(function (res) { console.log(res) }, function (error) { console.log(error) })
  • Tandem Promise

    • The Promise object’s then() method returns a new Promise object
    • The subsequent then() method registers the callback for the Promise returned by the previous then
    • The return value of the callback function from the previous then() method is taken as an argument to the callback from the subsequent then() method
    • If the callback returns a Promise, the callback to the subsequent then() method waits for it to end
    • So Promise can be chained. Each then() method is essentially a callback to the explicit state of the Promise object returned by the previous then() method.
    let p1 = new Promise(function(resolve, reject) {
      resolve(42);
    })
    
    p1.then(function (value) {
      console.log(value)
    }).then(function () {
      console.log("Finished")
    })
    
    // 42
    // Finished
  • Capture the error

    • The OnRejected callback is executed when a Promise fails or an exception occurs.
    • The catch() method is equivalent to the second argument taken by the then() method, but the difference is that the catch() method in the Promise chain allows us to catch errors that occurred in the completion or rejection handler of the previous Promise.
    let p1 = new Promise(function(resolve, reject) { throw new Error("Explosion") }) p1.catch(function (error) { console.log(error.message) throw new Error("Boom")  }).catch(function (error) { console.log(error.message) })
  • Promise static methods

    /* Promise.resolve() */ let promise = Promise.resolve(42) promise.then(function (value) { console.log(value) // 42 }) /*  Promise.reject() */ let promise = Promise.reject(42) promise.catch(function (value) { console.log(value) // 42 })
    (function (value) {console.log(value)}) new Promise(function (value) {console.log(value)}) new Promise(function (value) {console.log(value)}) new Promise(function (value); reject) { resolve('foo') })
  • Promise parallel execution

    /* Promise.all() * This method takes a single iterable object (such as an array) as an argument and returns a Promise. * The returned Promise will not be completed until all iterable Promise elements have been completed. */ let p1 = new Promise(function (resolve, reject) { resolve(42) }) let p2 = new Promise(function (resolve, reject) { reject(43) }) let p = Promise.all([p1, p2]) p.catch(function (value) { console.log(value) // 43 })
    /* Promise.race() * This method also accepts a Promise iterable object and returns a new Promise. * Once one of the source promises is resolved, the returned Promise is resolved immediately. */ let p1 = Promise.resolve(42) let p2 = new Promise(function (resolve, reject) { resolve(43) }) let p = Promise.race([p1, p2]) p.then(function (value) { console.log(value) // 42 })

Macro tasks and microtasks

The callback queueThe task is called
Macro task. Additional requirements can be added temporarily during the execution of macro tasks. You can choose to be one
New macro taskEntering the task queue can also be queued as
The current task
Micro tasks.
Execute immediately after the end of the current task.
Micro taskscan
Improve overall responsiveness, Promise callbacks are executed as microtasks. You can use
setTimeOut()add
Macro task.

console.log("global start")

setTimeOut(() => {
    console.log("setTimeOut")
}, 0)

Promise.resolve()
.then(() => {
    console.log("Promise")
})
.then(() => {
    console.log("Promise2")
})

console.log("global end")

// global start
// global end
// Promise
// Promise2
// setTimeOut

Generator

The Generator performs the following procedure:

  • The function name is defined with a * sign before it
  • When the Generator function is called, the function is not immediately executed; instead, a Generator object is obtained
  • When we call thisGenerator objectnext()When the method will goperform
  • It’s going to go all the way toyieldThe location of the keyword and the location of theThe value after yield returnGo out, and then the function will pause.Yield a return valueIt will be received in the form of{ value: "foo", done: false }
  • When we call the next() method again and pass in arguments, the function will continue, and the arguments we pass in will be returned as the yield value
  • If we were calling the throw() method of the generator object outside, the function would get this exception. You can use a try inside a function… catch… The way to catch exceptions

    function * main () { const users = yield ajax('/api/users.json') console.log(users) const posts = yield ajax('/api/posts.json') console.log(posts) } const g = main() const result = g.next() result.value.then(data => { const result2 = g.next(data) if (result2.done) return result2.value.then(data => { ... })})

Async/Await

  • Execute the async function, which returns both Promise objects

    async function test1 () { return 1 } async function test2 () { return Promise.resolve(2) } const result1 = test1() const  result2 = test2() console.log('result1', result1) console.log('result1', result1)
  • Promise. Then () succeeds, corresponding to await

    async function test3 () {
      const p3 = Promise.resolve(3)
      p3.then(data => {
          console.log('data', data)
      })
      
      const data = await p3
      console.log('data', data)
    }
    async function test4 () {
      const data4 = await 4
      console.log('data4', data4)
    }
    
    async function test5 () {
      const test5 = await test1()
      console.log('test5', test5)
    }
  • Promise. Catch () exception, corresponding to try... catch

    Sometimes we want to not interrupt a subsequent (asynchronous) operation even if the previous one fails. You can use it at this point
    try... catch...To catch exceptions

    async function test6 () {
      const p6 = Promise.reject(6)
      try {
         const data6 = await p6
         console.log('data6', data6)
      } catch (e) {
          console.log('e', e)
      }
    }

thanks

  • Thanks to every Programmer who has contributed to JavaScript. And thank you to all the lurkers who are making an effort. I look forward to seeing you explode.
  • Mr. Ruan Yifeng
  • Mr. Nicholas
  • “IT course master” at station B