Promise Knowledge Points Supplement

foreword

Most of the content of this article comes from the ES6 introductory tutorial written by Ruan Yifeng, and the original link is at the end of the article.

This article is a concise version of personal arrangement.

What is Promise

    Promise是一个对象,从它可以获取异步操作的消息。 Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。

Features of Promises

  • The state of the object is not affected by the outside world. Promise has three states, pending(in progress), resolved(completed, also known as fulfilled) and rejected(failed). Only the result of an asynchronous operation can determine which state it is currently in, and no other operation can change this state.

  • Once the state changes, it will not change again, and this result can be obtained at any time. There are only two possible changes to the state of the Promise object: from pendingchange to resolvedor from pendingchange to rejected. As long as these two conditions occur, the state will not change again.

Problems Promises Solve

  • Promise can express asynchronous operations in the process of synchronous operations, avoiding layers of nested callback functions, commonly known as回调地狱
  • Promise provides a unified interface that makes asynchronous operations easier.

Disadvantages of Promises

  • Promise cannot be canceled, it will be executed immediately once it is created, and cannot be canceled halfway
  • If the callback function is not set, the error thrown inside the Promise will not be reflected to the outside
  • When in pendinga state, it is impossible to know which state it is currently progressing to

basic usage

The Promise object is a constructor used to generate Promise instances.

The following code creates a Promise instance

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

  if (/* 异步操作成功 */){
    
    
    resolve(value);
  } else {
    
    
    reject(error);
  }
});

Promise accepts a function as a parameter, the two parameters of the parameter are resoleveand reject, they are two functions.

resolveThe function of the function is to pendingchange the state of Promise resolvedto call when the asynchronous operation is successful, and pass the result of the asynchronous operation as a parameter.

rejectThe function of the function is to pendingchange the state of Promise reject, call when the asynchronous operation fails, and pass the error reported by the asynchronous operation as a parameter.

After the Promise instance is generated, the state and the callback function of the state can thenbe specified through the method .resolvedreject

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

thenmethod can accept two callback functions as parameters. The first callback function is called when the state of the Promise object changes to Resolved, and the second callback function is called when the state of the Promise object changes to Reject. Among them, the second function is optional and does not have to be provided. Both functions accept the value passed from the Promise object as an argument.

then method

thenThe method is defined on the prototype object Promise.prototype, and its function is to add a callback function when the state changes to the Promise instance.

thenThe method returns a new Promise instance, so you can use chain writing, that is, thencall another thenmethod after the method.

getJSON("/posts.json").then(function(json) {
    
    
  return json.post;
}).then(function(post) {
    
    
  // ...
});

The above code usage thenmethod specifies two callback functions in turn. After the first callback function is completed, the returned result will be passed as a parameter to the second callback function.

catch method

catchmethod is actually .then(null,rejection)an alias for specifying a callback function when an error occurs.

getJSON("/posts.json").then(function(posts) {
    
    
  // ...
}).catch(function(error) {
    
    
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});

ResolvedIt is not valid to throw an error if the Promise state has already changed .

var promise = new Promise(function(resolve, reject) {
    
    
  resolve('ok');
  throw new Error('test');
});
promise
  .then(function(value) {
    
     console.log(value) })
  .catch(function(error) {
    
     console.log(error) });
// ok

Errors of Promise objects have a "bubbling" nature and will be passed backwards until they are caught. That is, errors will always be caught by the next catch statement.

In general, don't thendefine Rejectthe callback function of the state (ie thenthe second parameter of the method) in the method, always use catchthe method.

// bad
promise
  .then(function(data) {
    
    
    // success
  }, function(err) {
    
    
    // error
  });

// good
promise
  .then(function(data) {
    
     //cb
    // success
  })
  .catch(function(err) {
    
    
    // error
  });

In the above code, the second way of writing is better than the first way of writing, because the second way of writing can catch thenerrors in the execution of the previous method, and it is also closer to the synchronous way of writing (try/catch).

try/catchDifferent from the traditional code block, if catchthe error handling callback function is not specified by the method, the error thrown by the Promise object will not be passed to the outer code, that is, there will be no response.

It should be noted that catchthe method returns a Promise object, so thenthe method can be called later.

var someAsyncThing = function() {
    
    
  return new Promise(function(resolve, reject) {
    
    
    // 下面一行会报错,因为x没有声明
    resolve(x + 2);
  });
};

someAsyncThing()
.catch(function(error) {
    
    
  console.log('oh no', error);
})
.then(function() {
    
    
  console.log('carry on');
});
// oh no [ReferenceError: x is not defined]
// carry on

all method

allThe method is used to wrap multiple Promise instances into a new Promise instance.

var p = Promise.all([p1, p2, p3]);

In the above code, Promise.allthe method accepts an array as a parameter, and p1, p2, and p3 are all instances of Promise objects. If not, the method mentioned below will be called first, and the Promise.resolveparameters will be converted into Promise instances before further processing.

The state of p is determined by p1, p2, and p3, which are divided into two situations.

  • Only when the states of p1, p2, and p3 are all changed fulfilled, the state of p will change fulfilled. At this time, the return values ​​of p1, p2, and p3 form an array and pass it to the callback function of p.

-As long as one of p1, p2, and p3 is rejected , rejectedthe state of p will change rejected. At this time, the return value of the first rejected instance will be passed to the callback function of p.

race method

raceThe method is also to wrap multiple Promise instances into a new Promise instance

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

In the above code, as long as one instance among p1, p2, and p3 changes state first, the state of p will change accordingly. The return value of the first changed Promise instance is passed to p's callback function.

The parameters of the Promise.race method are the same as those of the Promise.all method. If it is not a Promise instance, the Promise.resolve method mentioned below will be called first, and the parameters will be converted into Promise instances before further processing.

The following is an example. If the result is not obtained within the specified time, the state of the Promise is changed to reject, otherwise it is changed to resolve.

var p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    
    
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
])
p.then(response => console.log(response))
p.catch(error => console.log(error))

In the above code, if the fetch method fails to return a result within 5 seconds, the state of the variable p will change rejected, thus triggering catchthe callback function specified by the method.

resolve method

Sometimes it is necessary to convert an existing object into a Promise object, and resolvethe method plays this role.

resolveis equivalent to the following

Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

reject method

rejectmethod returns a new Promise instance whose state is rejected. Its parameter usage resolveis exactly the same as the method.

var p = Promise.reject('出错了');
// 等同于
var p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, function (s){
    
    
  console.log(s)
});
// 出错了

done method

The callback chain of the Promise object, no matter whether it ends with thena method or catcha method, if the last method throws an error, it may not be caught (because the error inside the Promise will not bubble up to the global). Therefore, we can provide a donemethod that is always at the end of the callback chain, guaranteed to throw any errors that may arise.

asyncFunc()
  .then(f1)
  .catch(r1)
  .then(f2)
  .done();

Its implementation code is quite simple

Promise.prototype.done = function (onFulfilled, onRejected) {
    
    
  this.then(onFulfilled, onRejected)
    .catch(function (reason) {
    
    
      // 抛出一个全局错误
      setTimeout(() => {
    
     throw reason }, 0);
    });
};

As can be seen from the above code, donethe method can be used like thena method, providing a callback function Fulfilledwith Rejectedstate, or not providing any parameters. Either way, doneany errors that might arise are caught and thrown globally.

finally method

finallyMethods are used to specify actions that will be performed regardless of the final state of the Promise object. The biggest difference between it and donethe method is that it accepts an ordinary callback function as a parameter, regardless of the state, the function must be executed anyway.

Here is an example where the server handles the request using a Promise and then finallyshuts down the server using the method

server.listen(0)
  .then(function () {
    
    
    // run test
  })
  .finally(server.stop);

Its implementation is also very simple.

Promise.prototype.finally = function (callback) {
    
    
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => {
    
     throw reason })
  );
};

Application: loading images

We can write the loading of the image as a Promise, and once the loading is complete, the state of the Promise changes.

const preloadImage = function (path) {
    
    
  return new Promise(function (resolve, reject) {
    
    
    const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = path;
  });
};

reference documents

Promise - Ruan Yifeng

Guess you like

Origin blog.csdn.net/Dax1_/article/details/125489548