async/await, understand? Talk about promises for interview questions and practical use

  In the last blog, we explained Promises from the perspective of practical use and interviews (for the original text, please refer to " Talking about Promises for Interview Questions and Practical Use "), but although the Promise method solves the callback hell, this method is full of Promise  then() methods. If the processing flow is complex, the entire code will be full  then, and the code flow cannot well represent the execution flow.

Why async/await

  In es6, we can use the Generator function to control the flow, as in the following code:

function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}

  next()We can control the flow of the function based on how the Generator object is continuously called . But that doesn't seem so semantic. Therefore, the syntactic sugar async function of the Generator function is encapsulated in ES6, but it is defined in es7. The functions defined by ES7 async finally give JavaScript the ultimate solution for asynchronous operations. Async Functions are syntactic sugar for Generator functions. Use the keyword  Async to indicate asynchrony, and use await inside the function to indicate asynchrony. Compared with the Generator, the improvement of the Async function lies in the following points: the execution of the Generator function must rely on the executor, and the  Async() function has its own executor, and the calling method is the same as that of the ordinary function. Async And await is  more semantic than  * and  .  The return value of the function is a Promise object, which is more convenient than the Iterator object returned by the Generator function, and can be  called directly using the method.yieldasyncthen()

  So, let's illustrate the usage of the async/await function through a small piece of code:

    Timing functions that do not use async/await:

fn = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 2000)
  })
}
const Fn = () =>{
  fn().then((res) => {
    console.log(res)
  })
}
Fn()
console.log(2)

  I believe that all the programmers who can see here should know the output status of this code: print 2 first, and then print 1 after 2s.

    Timing functions using async/await:

fn = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 2000)
  })
}
const Fn = async () => {
  await fn().then((res) => {
    console.log(res)
  })
}
Fn()
console.log(2)

  The output of this function is: 1 is printed after 2s, and then 2 is printed.

  So, why?

  We take these two words async and await literally: async means asynchronous, async is used to define an asynchronous function that returns a Promise. ; await means to wait, Promise is a promise, await is also a promise. The promise of Promise is to output the return value to the return function of then, whether it succeeds or fails. The promise of await is that whether it's windy or rainy, I'll wait for you to finish doing the other steps. Therefore, in the above code that uses async/await, it will wait for the fn to run completely and the asynchronous callback to complete the processing of the return value before starting the next operation. The idea is to turn an asynchronous function into a synchronous operation.

practical use

  In last week's work, I used async/await many times in a crawler operation based on node to control the execution flow of the program:

//伪代码
let axiosArr = [];
for (let i = 0, len = arr.length; i < len; i++) {
  let params = qs.stringify({
    'param': arr[i].index,
  })
  axiosArr.push(axios.post(url, params, {
    headers
  }))
}
/*
*The above loop is to fetch 2345 pieces of data in a loop, and each data needs to access 16 interfaces on average
*Use axios.all to ask at the same time, when the return is over, the return value will be processed
*Then store the return value into the mongodb database
*/
await axios.all(axiosArr).then(
  axios.spread(function () {
    for (let i = 0, len = arguments.length; i < len; i++) {
      let str = `${unescape(arguments[i].data.replace(/\\u/g, '%u'))}`;
      str = basics.subStr(basics.deletN(basics.deletS(basics.cutStr(str))));
      concentArr[i].concent = str
    }
    mg.mongodbMain({
      name: obj.name,
      alias: obj.alias,
      type: type,
      url: obj.url,
      drugsConcent: concentrateArr
    })
  }))

  In fact, the operation is so simple, everyone will understand if you look at the code. But the problem is that when I don't use async/await, I will first access 2000+ data and continuously access its 16 interfaces, but because the then callback function of promise is asynchronous, it will hang, and Instead of storing data directly into the database. This seems to be different from what we expected. Therefore, I use the async/await function here, use synchronous processing of asynchronous operations, and synchronize promises. When axios.all accesses the 16 interfaces of each piece of data, the data is directly stored in the database, and then the Going to the next layer of the loop, there are still 16 interfaces to access the next piece of data.

The aftermath of async/await

  We said that the async return value of a function is a Promise object.

const delay = timeout => new Promise(resolve=> setTimeout(resolve, timeout));
async function f(){
    await delay(1000);
    await delay(2000);
    await delay(3000);
    return 'done';
}

f().then(v => console.log(v)); // print 'done' after 6s

  Then once an exception is thrown internally, the state of the returned Promise object will change to the  reject state. The error thrown will be  catch received by the method callback function.

async function e(){
    throw new Error('error');
}
e().then(v => console.log(v))
.catch ( e => console.log(e)); // The thrown error will be caught by catch

  In addition, async has a similar feature to promise.all, that is, there is an await function at the internal point to report an error, and the subsequent execution will not be executed.

let fn1 = ()=>{
    return new Promise((resolve,reject) => {
        setTimeout(()=>{
            reject( 'Intentionally throwing an error' );
        },500);
    });
}

let fn2 = ()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(1);
        },500);
    });
}

let getList = async ()=>{
    let a = await fn1();
    let b = await fn2();
    return {first: a,second:b};
}
getList().then(result=> {
    console.log(result);
}).catch(err=> {
    console.log(err); // Due to the error reported by fn1, the status of async directly becomes rejected 
});

 

  When Promises appeared, we seemed to see the end of callback hell. When Async/Await came along, async finally wasn't a difficult thing.

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324851243&siteId=291194637