“The Newbies of Little Wo Shan” provides front-end developers with technical information and a series of basic articles. For a better user experience, please go to xhs-rookies.com/ to learn the latest articles.

preface

We have learned callback, Promise, Generator, async/await in the JavaScript series of MDN. In this article, the author will illustrate the history of asynchronous development with practical examples, and introduce the advantages and disadvantages of each implementation method, in order to help readers familiarize themselves with the historical process and grasp the context of asynchronous development.

asynchronous

A few decades ago, the navigation website, fresh and simple, no special function, just pure display, ready-made web pages lying quietly on the server, efficient without pressure, let a person like it very much.

Today, decades later, static pages are far from meeting the needs of users. Websites become more complex, and user interactions become more frequent, resulting in a large number of complex internal interactions. In order to solve this complexity, various system “patterns” have emerged, so that it is easy to obtain data externally and show it to users in real time.

Fetching external data is actually a “network call,” and that’s when the term “asynchronous” came into being.

Asynchrony refers to the non-simultaneous existence or occurrence of two or more objects or events (or the occurrence of more than one related thing without waiting for the completion of its predecessor)

Asynchronous callbacks

Asynchronous callbacks are simply functions that are passed as arguments to other functions that execute in the background. When the code running in the background ends, the callbacks function is called to notify you that the work is done, or that something interesting has happened.

scenario

let readFile = (path, callBack) = > {
  setTimeout(function () {
    callBack(path)
  }, 1000)
}

readFile('first'.function () {
  console.log('first readFile success')
  readFile('second'.function () {
    console.log('second readFile success')
    readFile('third'.function () {
      console.log('third readFile success')
      readFile('fourth'.function () {
        console.log('fourth readFile success')
        readFile('fifth'.function () {
          console.log('fifth readFile success')})})})})})Copy the code

Advantages:

  • Solve the synchronization problem (that is, solve the problem that when a task takes a long time, the following tasks queue up and take too long, making the execution of the program slow down)

Disadvantages:

  • Callback hell (multi-level nesting), will lead to logic chaos, high coupling, one change will lead to all changes, nesting for many times, complex error handling
  • Cannot use try… Catch to catch an error
  • Can’t return
  • Readability is poor

Promise

A Promise object represents a value that is not necessarily known when the Promise is created. It allows you to associate the eventual success return value or failure cause of an asynchronous operation with the appropriate handler. This allows asynchronous methods to return values as synchronous methods do: instead of returning the final value immediately, asynchronous methods return a promise to give the value to the consumer at some point in the future.

scenario

let readFile = (path) = > {
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      if(! path) { reject('error!!! ')}else {
        console.log(path + ' readFile success')
        resolve()
      }
    }, 1000)
  })
}

readFile('first')
  .then(() = > readFile('second'))
  .then(() = > readFile('third'))
  .then(() = > readFile('fourth'))
  .then(() = > readFile('fifth'))
Copy the code

Advantages:

  • Once the state changes, it never changes again, and you can get this result at any time
  • Asynchronous operations can be expressed as a flow of synchronous operations, avoiding layers of nested callback functions
  • The readability of callback hell has been somewhat resolved

Disadvantages:

  • Unable to cancel promise
  • When you are in a pending state, you cannot tell what stage you are currently in
  • Code redundancy and semantic ambiguity can also occur when there are a bunch of tasks

Generator

Generator functions are an asynchronous programming solution provided in ES6. Syntactically, the Generator function is a state machine that encapsulates multiple internal states and needs to use the next() function to continue the following code.

Characteristics of the

  • Function with (*) between function names
  • The function body uses yield expressions internally, and the function execution returns when yield is encountered

scenario

var readFile = function (name, ms) {
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      console.log(name + 'Finished reading')
      resolve()
    }, ms)
  })
}

var gen = function* () {
  console.log('to specify the generator')
  yield readFile('first'.1000)
  yield readFile('second'.2000)
  yield readFile('third'.3000)
  yield readFile('forth'.4000)
  yield readFile('fifth'.5000)
  return 'Done'
}
var g = gen()
var result = g.next()
result.value
  .then(() = > {
    g.next()
  })
  .then(() = > {
    g.next()
  })
  .then(() = > {
    g.next()
  })
  .then(() = > {
    g.next()
  })
Copy the code

Advantages:

  • Can control the execution of the function, can be used with co function library

Disadvantages:

  • Process management is not convenient (i.e. when phase 1 and phase 2 are executed)

Async and await

The async functions and await keywords were recently added to the JavaScript language. They are part of ECMAScript 2017 JavaScript edition (see ECMAScript Next Support in Mozilla). In simple terms, they are based on Promises syntectic candy that makes asynchronous code easier to write and read. Using them, asynchronous code looks more like old-fashioned synchronous code, so they’re well worth learning.

Scenario 1

var readFile = function (name, ms) {
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      console.log(name + 'Finished reading')
      resolve()
    }, ms)
  })
}

async function useAsyncAwait() {
  await readFile('first'.1000)
  await readFile('second'.2000)
  await readFile('third'.3000)
  await readFile('forth'.4000)
  await readFile('fifth'.5000)
  console.log('Async file read finished')
}
useAsyncAwait()
Copy the code

advantages

  • Built-in actuators. This means there is no need to call the next function or co module as generator

  • Wider applicability. Both async and await are followed by promise functions, and the original data type is converted to a Promise

  • The semantics are more clear and concise

    disadvantages

  • A lot of await code blocks (the program does not wait in place, but continues the event loop, waiting for the response to continue) and the program runs, each await waiting for the previous one to complete

In the code in Scenario 2, scenario 1, the pseudo-requests of second and third don’t actually depend on the results of first and second, but they have to wait for the previous one to complete before they can continue, and we want them to happen at the same time, so the correct action should be like this.

async function useAsyncAwait() {
  const first = readFile('first'.1000)
  const second = readFile('second'.2000)
  const third = readFile('third'.3000)
  const forth = readFile('forth'.4000)
  const fifth = readFile('fifth'.5000)
  console.log('Async file read finished')

  await first
  await second
  await third
  await forth
  await fifth
}
useAsyncAwait()
Copy the code

Here, we store the three Promise objects in variables that can start their associated processes at the same time.

conclusion

In this article we have looked at the history of JavaScript asynchracy: the use of callback, Promise, generator, async/await, advantages and disadvantages.

The history of advantages disadvantages
callback Synchronization issues are resolved Callback hell, poor readability, no try/catch, no return
promise Fixed the readability of callback hell somewhat Unable to cancel, many tasks, also exist semantic ambiguity
generator Can control the execution of the function, can be used with co function library Process management is not convenient (i.e. when to perform phase one and when to perform phase two)
async/await Semantics more clear, concise, built-in actuators Lack of clarity can cause a lot of await blocking (the program does not wait, but continues)Event loopWait until the response continues

Among the existing asynchronous solutions, async/await is used by the largest number of people, and it brings us the biggest benefits, namely the style of synchronous code, simple and clear semantics.

Related articles

  • MDN – asynchronous JavaScript
  • Ruan Yifeng – 4 methods of Asynchronous JavaScript programming
  • Gold digger – Detail the evolution of JavaScript asynchrony
  • Nuggets – Advantages, pitfalls and how to use async/await
  • JS asynchronous development process