Leave back to hell and enter the Promise Era

Keywords: Javascript IE network Google

brief introduction

In the JavaScript world, all code is executed by a single thread. As a result of this "defect", all network operations and browser events of JavaScript must be executed asynchronously, so the expected results are often different. Because of JS flexibility, callback callback function is generated, which takes function as parameter to obtain the expected results. This has a good performance in simple asynchronous operation, but in complex / multi-layer asynchrony, it will When it becomes scary, the code will look bloated and hard to maintain, which is called "callback to hell". In order to solve "callback hell", developers put forward "Promise" objects. Before ES6 was unified, Promise had various open source implementations. And most modern browsers support Promise objects. Even a few browsers that do not support Promise have rich solutions in the open source community. So you can use Promise safely and boldly to avoid "callback to hell".

  Project must be one of three states: Pending, Fulfilled, and Rejected. Once the Promise is resolve d or Rejected, it cannot be migrated to any other state (i.e. immutable).

Basic process:

  1. Initialize Promise state (pending)
  2. Execute then( )Register callback processing array (then method can be called multiple times by the same promise)
  3. Execute the fn function passed in Promise immediately, pass the resolve and reject functions inside Promise as parameters to fn, and handle according to the time of event mechanism
  4. The key in project is to ensure that the parameters onFulfilled and onRejected passed in by the then method must be executed in the new execution stack after the event cycle in which the then method is called.

The real chain promise means that after the current promise reaches the full state, the next promise begins
This article does not involve the principle and implementation, but only introduces the API of Promise and the corresponding common use.

API

API describe Remarks
then Callback function in resolve state
catch Status callback for rejected
all Package multiple Promise instances into a new Promise instance and return an array in the order of parameter array
allSettled Returns a promise that resolves after all given promises have been resolved or rejected, and each object describes the result of each promise. In the proposal, it is expected to join ES2020
race Wrap multiple Promise instances into one instance, and the return value is the instance that enters the completion state first No support for IE
resolve The instance status changes to success / acceptance, and the then method of the instance can be called to get the incoming value
reject The instance status changes to fail / reject. You can call the catch method of the instance to get the incoming value
finally Whether the instance state is accept or reject, the function that will be called finally in the chain call depends on the instance state ES9 added standard, poor compatibility

Usage scenarios

  1. then
var promise1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve('foo');
  }, 300);
});

promise1.then(function(value) {
  // expected output: "foo"
  console.log(value);
});
// expected output: [object Promise]
console.log(promise1);
  1. catch
var p1 = new Promise(function(resolve, reject) {
  resolve('Success');
});

p1.then(function(value) {
  console.log(value); // "Success!"
  throw 'oh, no!';
}).catch(function(e) {
  console.log(e); // "oh, no!"
}).then(function(){
  console.log('after a catch the chain is restored');
}, function () {
  console.log('Not fired due to the catch');
});

// The following actions are the same as above
p1.then(function(value) {
  console.log(value); // "Success!"
  return Promise.reject('oh, no!');
}).catch(function(e) {
  console.log(e); // "oh, no!"
}).then(function(){
  console.log('after a catch the chain is restored');
}, function () {
  console.log('Not fired due to the catch');
});

PS: if the instance state has not called reject, the catch will never call

// Throw an error and call the catch method most of the time
var p1 = new Promise(function(resolve, reject) {
  throw 'Uh-oh!';
});

p1.catch(function(e) {
  console.log(e); // "Uh-oh!"
});

// Errors thrown in asynchronous functions are not caught by catch
var p2 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    throw 'Uncaught Exception!';
  }, 1000);
});

p2.catch(function(e) {
  console.log(e); // Not execute
});

// Errors thrown after resolve() are ignored
var p3 = new Promise(function(resolve, reject) {
  resolve();
  throw 'Silenced Exception!';
});

p3.catch(function(e) {
   console.log(e); // Not execute
});
  1. all
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]
  • If the parameter passed in is an empty iteratable object, an Promise.
  • If the passed in parameter does not contain any promise, an asynchronous resolved is returned Promise . Note: in this case, Google Chrome 58 returns a * * already resolved * * status Promise.
  • In other cases, return a pending Promise . The returned promise will then asynchronously become complete or fail when all promises are completed or one promise fails. See below for an example of "asynchronous or synchronous for Promise.all.". The return values will be arranged in the order of promise within the parameter, not in the order of completion of the call to promise.
  1. allSettled
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));

// expected output:
// "fulfilled"
// "rejected"

One pending Promise The specified set of commitments that will be completed asynchronously once in each commitment has been completed, whether successfully achieved or rejected through. At that time, the handler of the returned promise passes an array as input, which contains the results of each promise in the original promises set

  1. race
var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 500, 'one');
});

var promise2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then(function(value) {
  console.log(value);
  // Both resolve, but promise2 is faster
});
// expected output: "two"

A pending Promise As long as a promise in a given iteration resolves or rejects, the value of the first promise is taken as its value to resolve or reject asynchronously (once the stack is empty).

  1. resolve
var promise1 = Promise.resolve(123);

promise1.then(function(value) {
  console.log(value);
  // expected output: 123
});

Returns a promise object that has been parsed with the given value. If the return value is a promise object, the promise object is returned directly.

  1. reject
Promise.reject("Testing static reject").then(function(reason) {
  // Not being invoked
}, function(reason) {
  console.log(reason); // "Testing static reject"
});

Promise.reject(new Error("fail")).then(function(result) {
  // Not being invoked
}, function(error) {
  console.log(error); // stacktrace
});

The static function Promise.reject returns a rejected Promise object. through the use of Error Getting the reason of the error is very helpful for debugging and selective error catching.

  1. finally
let doing = false;

var p1 = new Promise((resolve,reject)=>{
	// doing
  	if(doing){
    	resolve('success');
    }else{
    	reject('fail')
    }
})

p1.then((data)=>{
    // success
	console.log(data)
}).catch((err)=>{
    //fail
console.log(err)
}).finally((data)=>{
    // success OR fail
	console.log(data)
})

Return to one Promise . At the end of project, the specified callback function will be executed regardless of whether the result is fulfilled or rejected. This provides a way for code that needs to be executed after promise completes successfully.
This avoids the need for the same statement then() and catch() Each time.

practical application

Mainly talking about the use of all, catch and finally in the actual scene of React

  1. Scenario 1: when a page has multiple request data to load at the same time, you can use all to reduce the number of setstates to reduce the render, which has achieved performance optimization.
// Promise
const quest1,quest2,quest3,quest4;

const p = Promise.all([quest1,quest2,quest3,quest4]);

// The callback is an array parameter in the order of all array parameters
// If you don't use all, you need setState four times to process data separately, and render four times, which wastes performance
p.then(([data1,data2,data3,data4])=>{
  // doing
	this.setState({
  	data1,data2,data3,data4
  })
});
  1. Scenario 2: when a request needs to have a loading state to process, you can use catch to process the processing mode after the request fails, and finally to process the inevitable execution function (the loading state must be changed when the request is completed, no matter whether the request fails or succeeds)
// Promise
const quest1;

const p = Promise.all([quest1,quest2,quest3,quest4]);

// The callback is an array parameter in the order of all array parameters
// If you don't use all, you need setState four times to process data separately, and render four times, which wastes performance
quest1.then(data=>{
  // success doing
  console.log('Request successful');
}).catch(err=>{
	//fail doing
	console.log('request was aborted');
}).finally(res=>{
	this.setState({
  	loading:false
  })	
})

Compatibility handling

Most modern browsers support ES6, and a few (IE, mobile browser) do not support Promise. You can use the third-party plug-in bluebird or polyfill to solve the compatibility problem. The specific use method can be Baidu Get. The following figure shows Promise's compatibility chart

Published 27 original articles, won praise 4, visited 10000+
Private letter follow

Posted by goatboy on Tue, 11 Feb 2020 00:36:09 -0800