This is the sixth day of my participation in the First Challenge 2022. For details: First Challenge 2022.

In this article, we continue the asynchronous solution by introducing you to the asynchronous solution (1).

1, Promise

1.1 What is Promise?

Let’s start with some code:

const https = require('https');

function httpPromise(url){
  return new Promise(function(resolve,reject){
    https.get(url, (res) = > {
      resolve(data);
    }).on("error".(err) = > {
      reject(error);
    });
  })
}

httpPromise().then( function(data){
  // todo 
}).catch(function(error){ //todo })


httpPromise(url1)
    .then(res= > {
        console.log(res);
        return httpPromise(url2);
    })
    .then(res= > {
        console.log(res);
        return httpPromise(url3);
    })
    .then(res= > {
      console.log(res);
      return httpPromise(url4);
    })
    .then(res= > console.log(res)); .Copy the code

As you can see from the example above, a Promise receives an executor in which we need to “fill in” the target’s asynchronous task.

As soon as a Promise instance is created, the logic in the executor executes, deciding how to use resolve or Reject to change the state of the Promise instance based on the result returned by the asynchrony.

1.2 Promise instance has three states:

  • Pending: Indicates that the file is in progress. This is an initial state after the Promise instance is created;
  • Resolved: Successfully completed. This is the state reached when we call resolve in the executor;
  • Rejected: Indicates that the operation fails or is rejected. This is the state we reach when we call reject in the actuator;

Once the wait state goes to another state it can never be changed, which means once it’s resolved it can’t be changed again.

Resolved or Pending -> Rejected

// When defined, the status defaults to pending
const p1 = new Promise((resolve, reject) = >{})// Resolve () changes to Resolved
const p2 = new Promise((resolve, reject) = > {
    setTimeout(() = > {
        resolve()
    })
})

// Reject (), the state changes to Rejected
const p3 = new Promise((resolve, reject) = > {
    setTimeout(() = > {
        reject()
    })
})

// Return to an resolved state
Promise.resolve(100)
// Return a rejected state directly
Promise.reject('some error')
Copy the code
new Promise((resolve, reject) = > {
  resolve('success')
  / / is invalid
  reject('reject')})Copy the code

When we construct a Promise, the code inside the constructor executes immediately.

new Promise((resolve, reject) = > {
  console.log('new Promise')
  resolve('success')})console.log('finifsh')
// new Promise -> finifsh
Copy the code

1.3 Status and then Catch

A state change triggers a then catch

  • Pending does not trigger any then catch callbacks
  • Switching to Resolved triggers subsequent THEN callbacks
  • Changing the status to Rejected triggers a subsequent catch callback

Then catch will continue to return a Promise, and a state change may occur!!

// Then () normally returns a promise in the Resolved state
Promise.resolve().then(() = > {
    return 100
})

// Then () throws an error and returns a promise in the Rejected state
Promise.resolve().then(() = > {
    throw new Error('err')})// Catch () does not throw an error and returns a Promise in the Resolved state
Promise.reject().catch(() = > {
    console.error('catch some error')})// Catch () throws an error, which returns a promise in the Rejected state
Promise.reject().catch(() = > {
    console.error('catch some error')
    throw new Error('err')})Copy the code

2, I Promise

2.1 Promise characteristics

What are the features of Promise, and what are its advantages and disadvantages? What is the Promise chain? What is the difference between Promise constructor execution and THEN execution?

Features: implementation of chain call

Pros: Promise solves the callback hell problem nicely

Cons: You can’t cancel promises, and errors need to be caught with callback functions.

Promise chain:

  • Each call to THEN returns a brand new Promise, so the then method can then be used to form the Promise chain
  • If return is used in then, the value of return is wrapped in promise.resolve ()

What’s the difference between Promise constructor execution and then execution:

  • When you build a Promise, the code inside the constructor executes immediately
  • The then function is executed after promise.resolve()

2.2 code problem

/ / 1
Promise.resolve().then(() = > { 
  // Return resolved with no error
    console.log(1)   / / 1
}).catch(() = > {
    console.log(2)   / / will not go
}).then(() = > {
    console.log(3)  / / 3
}) // resolved

// Result 1 3

/ / the second question
Promise.resolve().then(() = > { 
    console.log(1) 
  	// Return the Promise in the Rejected state
    throw new Error('erro1')
}).catch(() = > { 
  // 返回 resolved 状态的 promise
    console.log(2)
}).then(() = > {
    console.log(3)})// Result 1, 2, 3

/ / the third topic
Promise.resolve().then(() = > { // Return the Promise in the Rejected state
    console.log(1)
    throw new Error('erro1')
}).catch(() = > { // 返回 resolved 状态的 promise
    console.log(2)
}).catch(() = > {
    console.log(3)})// Result 1 2
Copy the code

3, the Generator

What a Generator is:

One feature of the Generator that benefits asynchrony is that it can be interrupted in the middle of execution and then woken up by us after a certain amount of time. With this “wake up after interrupt” mechanism, we can think of the Generator as a container for asynchronous tasks and use the yield keyword to wait for asynchronous tasks.

function firstAjax() {
  ajax(url1, () = > {
    / / call secondAjax
    secondAjax()
  })
}

function secondAjax() {
  ajax(url2, () = > {
    // Process logic
  })
}

ajax(url, () = > {
  / / call firstAjax
  firstAjax()
})
Copy the code

We can solve the problem of callback hell with Generator functions. We can rewrite the previous callback hell example as follows:

function *fetch() {
    yield ajax(url, () = > {})
    yield ajax(url1, () = > {})
    yield ajax(url2, () = >{})}let it = fetch()
let result1 = it.next()
let result2 = it.next()
let result3 = it.next()
Copy the code

Finding the Generator is a bit of a hassle, and.next() is required for each iteration to continue until done is true. So we use a third party library (CO) to execute directly:

What co is: an auto-executing function of a generator function.

const co = require('co');
co(httpGenerator());
Copy the code

4, async/await

4.1 Background of async/await generation

  • Asynchronous callback
  • Promise then catch chain calls, but also based on callback functions
  • Async /await is synchronous syntax and eliminates callback functions completely

4.2 the use of

If async is added to a function, the function returns a Promise

async function test() {
  return "1"
}
console.log(test()) // -> Promise {<resolved>: "1"}
Copy the code

Async wraps the return value of a function in promise.resolve (), as in then, and await can only be used with async.

Write asynchrony in a synchronous way.

function loadImg(src) {
    const promise = new Promise((resolve, reject) = > {
        const img = document.createElement('img')
        img.onload = () = > {
            resolve(img)
        }
        img.onerror = () = > {
            reject(new Error('Image load failed${src}`))
        }
        img.src = src
    })
    return promise
}

async function loadImg1() {
    const src1 = 'http:xxx.png'
    const img1 = await loadImg(src1)
    return img1
}

async function loadImg2() {
    const src2 = 'https://xxx.png'
    const img2 = await loadImg(src2)
    return img2
}

(async function () {
    // Note: await must be placed in async function otherwise an error will be reported
    try {
        // Load the first image
        const img1 = await loadImg1()
        console.log(img1)
        // Load the second image
        const img2 = await loadImg2()
        console.log(img2)
    } catch (ex) {
        console.error(ex)
    }
})()
Copy the code

4.3 Typical Scenario

4.3.1 concurrent

The following code simulates three request interfaces, i.e., three requests with no dependencies wait until the last one is finished before executing the next one, resulting in a waste of time.

(async() = > {const getList1 = await getList1();
  const getList2 = await getList1();
  const getList3 = awaitgetList2(); }) ();Copy the code

Solution:

(async() = > {const listPromise = getList();
  const anotherListPromise = getAnotherList();
  await listPromise;
  awaitanotherListPromise; }) ();// Can also be used
(async() = > {Promise.all([getList(), getAnotherList()]).then(...) ; }) ();Copy the code

4.3.2 Catching errors

Using try catch to catch errors can cause code clutter when we need to catch multiple errors and do different things:

async function asyncTask(cb) {
    try {
       const res1 = await request1(resByRequest1);  //resByRequest1 returns a promise
       if(! res1)return cb('error1');
    } catch(e) {
        return cb('error2');
    }

    try {
       const res2 = await request2(resByRequest2); //resByRequest2 returns a promise
    } catch(e) {
        return cb('error3'); }}Copy the code

Simplify error catching by adding an intermediate function:

export default function to(promise) {
   return promise.then(data= > {
      return [null, data];
   })
   .catch(err= > [err]);
}
Copy the code

Error catching code:

async function asyncTask() {
     let err, data
     [err, data1] = await to(resByRequest1);
     if(! data1)throw new Error('xxxx');
  
     [err, data2] = await to(resByRequest2);
     if(! data2)throw new Error('xxxx');
}
Copy the code

5. Relationship between async/await and Promise

  • Async functions return Promise objects (if no Promise is returned in the function, it will be wrapped automatically)
  • Await is equivalent to then of Promise
  • try… Catch catches exceptions instead of the catch of Promise
async function fn2() {
    return new Promise(() = >{})}console.log( fn2() )

async function fn1() { // Perform async and return a Promise object
    return 100
}
console.log( fn1() ) // equivalent to promise.resolve (100)
Copy the code
  • Await followed by a Promise object: blocks subsequent code and waits for the state to become resolved before getting the result and continuing
  • Await followed by non-promise objects: will return directly
(async function () {
    const p1 = new Promise(() = > {})
    await p1
    console.log('p1') // Will not be executed}) () (async function () {
    const p2 = Promise.resolve(100)
    const res = await p2
    console.log(res) / / 100}) () (async function () {
    const res = await 100
    console.log(res) / / 100}) () (async function () {
    const p3 = Promise.reject('some err')
    const res = await p3
    console.log(res) // Will not be executed}) ()Copy the code

try… Catch Catches the Rejected state

(async function () {
    const p4 = Promise.reject('some err')
    try {
        const res = await p4
        console.log(res)
    } catch (ex) {
        console.error(ex)
    }
})()
Copy the code

In general:

  • Async encapsulation Promise
  • Await processing Promise success
  • try… The catch processing Promise failed

6. Asynchronous nature

Await is synchronous, but it is still an asynchronous call in nature.

async function async1 () {
  console.log('async1 start')   / / 2
  await async2() 
  console.log('async1 end') / / 5
}

async function async2 () {
  console.log('async2') / / 3
}

console.log('script start')  / / 1
async1()
console.log('script end') / / 4
Copy the code

7, async and await

What are the advantages and disadvantages of async and await? What is the principle of await?

Features:

  • A function returns a Promise if async is added to it. Async wraps the return value of the function in promise.resolve (), just like the return value of the then processing
  • Await can only be used with async and cannot be used alone

Advantages:

  • The advantage over Promise is the ability to write a much clearer invocation chain, as well as the elegant solution to callback hell

Disadvantages:

  • Because await turns asynchronous code into synchronous code, performance degrades if there is no relationship between multiple asynchronies

Principle:

  • Await is a syntactic sugar of generator plus Promise, and an automatic execution generator is implemented internally

8. Reference links

Let’s talk about Async