Solutions to asynchronous programming -- promise and await

Keywords: Front-end JSON github ECMAScript

What is promise?

Promise, in short, is a container that holds the results of an event (usually an asynchronous operation) that will end in the future. Syntactically, promise is an object from which messages for asynchronous operations can be obtained. Promise provides a unified API, and all kinds of asynchronous operations can be processed in the same way. In short, promise is used to express asynchronous operations in the process of synchronous operations, avoiding nested callback functions.

Features of promise

① the state of the object is not affected by the outside world: there are three states of promise asynchronous operation: in progress, succeeded and failed. Only asynchronous operations can change this state. ② one change is unchanged: once the promise state is changed, it will not change again. There are two possibilities for the promise object to change: in progress - > succeeded, in progress - > failed.

Basic usage of promise

The promise object is a constructor used to generate promise instances
Example:

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* Asynchronous operation succeeded */){
    resolve(value);
  } else {
    reject(error);
  }
});

The parameters accepted are resolve and reject
Role of resolve: the state of promise object is completed by in progress - >. The result of the asynchronous operation is passed as a parameter
The role of rejected: the state of the project object has been failed by in progress - > and the reason of asynchronous failure is passed as a parameter.
Note: calling resolve or reject does not terminate the execution of the project's parameter function
Example:

new Promise((resolve, reject) => {
  resolve(1);
  console.log(2);
}).then(r => {
  console.log(r);
});
// 2
// 1

After the above code calls resolve (1), the subsequent console(2) will execute and print out first. This is because the immediate resolved promise is executed at the end of this round of event cycle, always later than the synchronization task of this round.

The usage of then

After the promise instance is generated, the callback functions of the resolved state and the adjusted state are specified with the then method.
Example:

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

The then method can take two callback functions as parameters. The first callback function is called when the project object state is resolve (completed), and the second callback function (optional) is called when the project object state is reject (failed).
For example:

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(100).then((value) => {
  console.log(value);
});
// The result is done

The then usage of chain

The then method returns a new Promise instance (note, not the original Promise instance). So we can use chain writing, that is, the then method is followed by another then method
Example

getJSON("/post/1.json").then(function(post) {
  return getJSON(post.commentURL);
}).then(function funcA(comments) {
  console.log("resolved: ", comments);
}, function funcB(err){
  console.log("rejected: ", err);
});

In the above code, the callback function specified by the first then method returns another Promise object. At this point, the callback specified by the second then method waits for the state of the new Promise object to change. If it changes to resolved, funcA is called, and if the status changes to rejected, funcB is called.

catch method

In the project object, if the asynchronous operation throws an error, the status will change to rejected, and the callback function specified by the catch method will be called to handle the error. In addition, if the callback function specified by the then method throws an error during operation, it will also be caught by the catch method.
Example:

p.then((val) => console.log('fulfilled:', val))
  .catch((err) => console.log('rejected', err));

// Equate to
p.then((val) => console.log('fulfilled:', val))
  .then(null, (err) => console.log("rejected:", err));

The error of the promise object has the property of "bubbling" and will be passed back until it is caught, that is, it will skip the middle then function
Example:

 getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // Handling errors from the first three promises
});

finally method

The finally method is used to specify the operation that will be performed regardless of the final state of the promise object.
Example

server.listen(port)
  .then(function () {
    // ...
  })
  .finally(server.stop);

For example, the server uses promise to process requests, and then uses the finally () method to shut down the server.

promise.all () method

The promise.all method is used to wrap multiple promise instances into a new promise instance.
For example, const p = Promise.all([p1, p2, p3]);
The Promise.all method accepts an array as a parameter, and the elements in it are promise instances. If not, the parameter will be automatically converted to promise instances.
The state of p is determined by the elements in its array. It can be divided into two states (use the above example)
① only when the state of p1 p2 p3 becomes completed can it become completed. At this time, the return value of p1 p2 p3 forms an array and is passed to the callback function of p.
② only one of p1 p2 p3 is rejected, and the state of p will become rejected. At this time, the return value of the first instance rejected will be passed to the callback function of p.
Example:

const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result);

const p2 = new Promise((resolve, reject) => {
throw new Error('Wrong report');
})
.then(result => result);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: enter code here

promise.race() method

Promise.race method also packages multiple promise instances into a new promise instance

const p = Promise.race([p1, p2, p3]);

If p1 p2 p3 is not a promise instance, it will also be automatically converted to a promise instance
Different from promise.all, in the above code, only one instance of p1, p2 and p3 is used to change the state first, and the state of p changes with it. The return value of the Promise instance that first changed is passed to the callback function of p.

What is async function

The introduction of async makes asynchronous operation more convenient. What is async function? In fact, it is the syntax sugar of generator function. Make asynchronous function and callback function look more like synchronous function in syntax. Generator is not introduced here. Let's go straight to async

Basic usage of async

The async return value is a promise object, so you can use the then method to add a callback function. When the function is executed, once it encounters the await, it will return first, wait until the asynchronous operation is completed, and then execute the later content in the function body.
Example:

async function getStockPriceByName(name) {
  const symbol = await getStockSymbol(name);
  const stockPrice = await getStockPrice(symbol);
  return stockPrice;
}

getStockPriceByName('goog').then(function (result) {
  console.log(result);
});

The usage of async function

//Function declaration
async function foo(){}
//Function expression
const foo = async function(){};
//Object method
let obj = {async  foo(){}};
obj.foo().then(...)
//class method
class Storage{
consttuctor(){
    this.cachePromise=caches.open('avatars');
    }
    async getAvatar(name){
    const cache = await this.cachePromise;
    return cache.match('/avatars/${name}.jpg')};
    }
}

const storage =new Storage();
storage.getAvatar('jake').then(....);
}
}

const storage =new Storage();
storage.getAvatar('jake').then(...)

//Arrow function
const foo =async()=>{};

The value returned by the return statement within the async function becomes the parameter of the then method call function.
Example:

async function getTitle(url) {
  let response = await fetch(url);
  let html = await response.text();
  return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"

await command

Normally, the await command is followed by a promise object. If it is not, it will be automatically converted to a promise object
Example:

async function f(){
return await 123;
}
f().then(v =>console.log(v))
//123

When the project after an await statement changes to reject, the whole function will be interrupted.
Example:

async function f() {
  await Promise.reject('Error');
  await Promise.resolve('hello world'); // Not execute
}

error handling

If there is an error in the asynchronous operation after await, the project object returned by the async function is reject ed Example:

async function f() {
  await new Promise(function (resolve, reject) {
    throw new Error('Error');
  });
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error: there is an error

Use the try.... catch code block lesson to prevent errors.
Example:

async function f() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('Error');
    });
  } catch(e) {
  }
  return await('hello world');
}

You can also place multiple await commands in the try..catch structure

async function main() {
  try {
    const val1 = await firstStep();
    const val2 = await secondStep(val1);
    const val3 = await thirdStep(val1, val2);

    console.log('Final: ', val3);
  }
  catch (err) {
    console.error(err);
  }
}

Attention points

① the await command can only be used in the async function, and an error will be reported when it is used in the ordinary function.

Posted by colemanm on Wed, 11 Dec 2019 20:03:15 -0800