Promise usage and async function of asynchronous operation in ES6

Time:2020-1-21

Promise basic usage

PromiseObject is a constructor used to generatePromiseExample.PromiseThe constructor takes a function as an argument, and its two arguments areresolveandreject

resolveThe function is called when the asynchronous operation succeeds(PromiseObject state frompendingTurn intofulfilled), and pass the result of the asynchronous operation as a parameter.

rejectThe function is called when an asynchronous operation fails(PromiseObject state frompendingTurn intorejected), and the error reported by the asynchronous operation is passed as a parameter.

const funPromise = function(options) {
  return new Promise(function(resolve, reject) {
    If (/ * asynchronous operation succeeded * /){
      resolve(result);
    } else {
      reject(error);
    }
  });
}

resolveIn addition to the normal value, the argument to the function may be anotherPromiseInstance, at this time, initialpromiseBased on the newPromiseInstance decision.

rejectMethod is equivalent to throwing an error. Equate tothrow new Error('error')

Promise.prototype.then()

PromiseExample hasthenMethod, its purpose is toPromiseThe callback function when the state of the instance is changed, that isPromiseAfter the instance is generated, use thethenMethods are specified separatelyfulfilledState andrejectedThe callback function for the state.

funPromise().then(function(result) {
  // fulfilled
}, function(error) {
  // rejected
})

thenMethod can take two callback functions as arguments. The first callback function isPromiseThe state of the object changes tofulfilledThe second callback function isPromiseThe state of the object changes torejectedWhen called. The second function is optional and does not have to be provided. Both functions acceptPromiseObject as a parameter.

thenMethod returns a newPromiseExample (note, not the original onePromiseExample). Therefore, the chain writing method can be adopted, i.ethenMethod to call anotherthenMethod to handle the previousthenMethod mediumreturnThe result.

funPromise().then(function(result) {
  return result.data;
}).then(function(data) {
  // fulfilled
});

The above code usesthenMethod, specifying two callback functions in turn. After the first callback function is completed, the returned result will be passed into the second callback function as a parameter. And, firstthenThe returned result can also be the result of another asynchronous operationPromiseObject, then the latterthenFunction, will wait for thePromiseThe state of the object changes before it is called.

funPromise().then(
  (result) => { return funPromise(result); }
).then(
  (data) => { /* fulfilled */ },
  (error) => { /* rejected */ }
);

In the above code, the firstthenMethod to return another callback functionPromiseObject. Now, the secondthenMethod and wait for the newPromiseObject state changes. If it becomesfulfilled, call the first callback function if the status changes torejected, call the second callback function.

Promise.prototype.catch()

PromiseExample hascatchMethod, its purpose is toPromiseInstance add status changes torejectedState callback function, that isthenMethod.

funPromise().then(function(result) {
  // fulfilled
}).catch(function(error) {
  //Handling errors that occurred when the funprompt and previous then callback functions were run
});

PromiseThe error of an object has a bubbling property and is passed back until it is caught. That is, no matter how many in frontthenFunction, the error will always be nextcatchStatement capture.

funPromise().then(function(result) {
  return funPromise(result);
}).then(function(data) {
  // fulfilled
}).catch(function(error) {
  //Handling errors from the first three promises
});

Generally speaking, do notthenMethod definitionrejectedThe callback function of the state (i.ethenAlways use thecatchMethod because it captures the previousthenError in method execution.

catchMethod returns aPromiseObject, andcatchIf no other errors are thrown, thePromiseThe object isresolvedStatus. And it can be called laterthenMethod, but the previouscatchCan’t capture the followingthenSo try tocatchIt’s all at the end.

Promise.all()

Promise.all()Method to use multiplePromiseExample, packaged as a newPromiseExample. It takes an array as a parameter, and the values in the array are allPromiseInstance, if not, it will callPromise.resolve()Method, converting parameters toPromiseExample, and then further processing.

const p = Promise.all([funPromise(1), funPromise(2), funPromise(3)]);

pThe state of is determined by the value in the array, which is divided into two cases.

  • ArrayPrimiseThe state of the instance becomesfulfilledpThe state offulfilledIn this case, the return values of the instances in the array form an array and are passed topThe callback function for.
  • As long as one of the instances of the array isrejectedpThe state ofrejected, the firstrejectThe return value of the instance of, that is, the error message, is passed to thepThe callback function for.
p.then(function (results) {
  //All fulfilled and results are an array, in which are the returned results of each instance
}).catch(function(error){
  //One of them becomes rejected
});

Note that if thePromiseInstance, self definedcatchMethod, then once it isrejected, does not triggerPromise.all()OfcatchMethod.

application

usePromiseObject implementationAjax

const getAjax = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState === 4 && this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onreadystatechange = handler;
    xhr.responseType = "json";
    xhr.setRequestHeader("Accept", "application/json");
    xhr.send();
  });
  return promise;
};

getAjax("/test.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  Console. Error ('error ', error);
});

Basic usage of async / await

WhenasyncWhen the function is executed, onceawaitWe’ll waitawaitAfter that, the asynchronous operation is completed, and then the statement after the function body is executed.

asyncFunction returns aPromiseObject, you can usethenMethod to add a callback function.asyncInternal functionreturnThe value returned by thethenMethod callback function.

async function f() {
  return 'hello dora';
}

f().then(v => console.log(v))   // "hello dora"

asyncIf an error is thrown within the function, the returnedPromiseObject becomesrejectedStatus. The error object thrown will becatchMethod callback received.

async function f() {
  Throw new error ('error ');
}

F(). Catch (E = > console. Log (E)) // error: error

Await command

Under normal circumstances,awaitThe command is followed by aPromiseObject that returns the result of the object. If notPromiseObject to return the corresponding value directly.

async function f() {
  Return await 123; // equivalent to return 123;
}

f().then(v => console.log(v))  // 123

awaitAfter commandPromiseObject if changed torejectedStatus, the error will becatchMethod received.

Any oneawaitAfter statementPromiseObject becomesrejectedState, then the wholeasyncThe function interrupts execution.

Sometimes, we hope that even if the previous asynchronous operation fails, we will not interrupt the subsequent asynchronous operation. There are two solutions:

The first way is toawaitPut ontry...catchIn the structure, no matter whether the asynchronous operation is successful or not, the following code will execute.

async function f() {
  try {
    Await promise.reject ('error ');
  } catch(e) { }
  return await Promise.resolve('hello dora');
}

f().then(v => console.log(v))   // hello dora

Another way is toawaitHinderPromiseObject followed by anothercatchMethod to handle previous errors.

async function f() {
  Await promise. Reject ('error '). Catch (E = > console. Log (E));
  return await Promise.resolve('hello dora');
}

f().then(v => console.log(v))
// wrong.
// hello dora

Points for attention

1. Error handling

As I said before,awaitAfter commandPromiseObject, the result may berejected, so the best way to prevent mistakes is toawaitCommand placedtry...catchCode block. If there are more than oneawaitCommand, can be placed in thetry...catchIn the structure, if there is only oneawait, you can use thecatchcaptureawaitHinderpromiseError thrown.

const superagent = require('superagent');
const NUM_RETRIES = 3;

async function test() {
  let i;
  for (i = 0; i < NUM_RETRIES; i++) {
    try {
      await superagent.get('/api/xxx');
      break;
    } catch(err) {}
  }
}

test();

In the above code, use thetry...catchStructure to achieve multiple repeated attempts. IfawaitIf the operation is successful, it will be usedbreakStatement exits the loop; if it fails, it will becatchStatement capture, and then go to the next cycle.

2. Multiple await asynchronous operations are executed concurrently

MultipleawaitIf there is no secondary relationship (i.e. mutual dependence) between the asynchronous operations after commands, it is better to let them trigger at the same time to shorten the execution time of the program.

// writing
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// writing two
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

3. When the parameters of array traversal methods such as foreach are async functions, they are executed concurrently

onlyasyncFunction internal is secondary execution, external is not affected, soforEach()map()The parameter of equal array traversal method is changed toasyncIs executed concurrently.

Function dbfuc() {// async is not required here
  let docs = [{}, {}, {}];

  //You get the wrong results
  docs.forEach(async (doc)=> {
    await funPromise(doc);
  });
}

The above code will get the wrong result because there are three reasonsfunPromise(doc)Operations are executed concurrently, that is, simultaneously, rather than subsequently. So the right way to write is to useforCycle.

async function dbFuc() {
  let docs = [{}, {}, {}];

  for (let doc of docs) {
    await funPromise(doc);
  }
}

If concurrent execution is required, use thePromise.all()Method.

async function dbFuc() {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => funPromise(doc));

  let results = await Promise.all(promises);
  return results;
}

There is a set of asynchronous operations that need to be completed in sequence.

async function logInOrder(urls) {
  //Read remote URL concurrently
  const textPromises = urls.map(async url => {
    const response = await fetch(url);
    return response.text();
  });

  //Output in order
  for (const textPromise of textPromises) {
    console.log(await textPromise);
  }
}

In the above code, althoughmapThe parameters of the method areasyncFunction, but it is executed concurrently because onlyasyncFunction internal is secondary execution, external is not affected. Hinderfor..ofUsed inside the loopawaitTherefore, the sequential output is realized.

Reference link:
Promise object
Async function