浅谈promise(then、catch、resolve、reject、race、all、done、finally)

抽象异步处理对象以及对其进行各种操作的组件

主要类型

  • Constructor 构造函数
  • Instance Method 实例方法
  • Static Method 静态方法

**promise.then(onFulfilled, onRejected)操作之后执行回调函数。**Fulfilled为执行成功调用的函数,onRejected为执行失败调用的函数。

promise.catch(onRejected)捕获到错误执行onRejected函数

promise状态

  • 只能由pending到fulfilled或Rejected
  • 状态不可逆
graph LR
Pending-->Fulfilled 
Pending-->Rejected
  1. 使用new Promise方法创建promise对象。
  2. .then.then添加promise对象的处理函数。

Promise.resolve/Promise.reject

静态方法Promise.resolve(value) 可以认为是 new Promise() 方法的快捷方式。


new Promise(function(resolve){
    resolve(42);
});

promise的链式写法(chain)

function taskA() {
    console.log("Task A");
}
function taskB() {
    console.log("Task B");
}
function onRejected(error) {
    console.log("Catch Error: A or B", error);
}
function finalTask() {
    console.log("Final Task");
}

var promise = Promise.resolve();
promise
    .then(taskA)
    .then(taskB)
    .catch(onRejected)
    .then(finalTask);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8gGAh3eC-1585579112930)(http://liubin.org/promises-book/Ch2_HowToWrite/img/promise-then-catch-flow.png)]

  • then 注册onFulfilled时的回调函数
  • catch 注册onRejected时的回调函数

链式写法的参数传递

function doubleUp(value) {
    return value * 2;
}
function increment(value) {
    return value + 1;
}
function output(value) {
    console.log(value);// => (1 + 1) * 2
}

var promise = Promise.resolve(1);
promise
    .then(increment)
    .then(doubleUp)
    .then(output)
    .catch(function(error){
        // promise chain中出现异常的时候会被调用
        console.error(error);
    });

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t66Chbo0-1585579112952)(http://liubin.org/promises-book/Ch2_HowToWrite/img/promise-then-passing-value.png)]

promise.all

Promise.all 接收一个 promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会去调用 .then 方法。

Promise.all([request.comment(), request.people()]);
  • request.comment()request.people()会同时执行(并行执行)。
  • promise的结果和传递给Promise.all的数组的顺序一致。

promise.race

Promise.race只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。

注:promise.race在第一个函数执行完毕后,并不会取消其他函数的执行状态,但是其余函数执行完毕之后不会再调用.then

then与catch

.catch 也可以理解为 promise.then(undefined, onRejected),但实际使用中我们还是会将then与catch分开使用。

建议多用catch方法,少用then方法的第二个参数

function throwError(value) {
    // 抛出异常
    throw new Error(value);
}
// <1> onRejected不会被调用
function badMain(onRejected) {
    return Promise.resolve(42).then(throwError, onRejected);
}
// <2> 有异常发生时onRejected会被调用
function goodMain(onRejected) {
    return Promise.resolve(42).then(throwError).catch(onRejected);
}
// 运行示例
badMain(function(){
    console.log("BAD");
});
goodMain(function(){
    console.log("GOOD");
});

//输出结果
`GOOD`
  • 使用.then即使 throwError 抛出了异常,onRejected 指定的函数也不会被调用。
  • 使用.catch因为是链式操作,会捕获到上一步.then中抛出的操作。

promise中的错误捕获

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

someAsyncThing().then(function() {
  console.log('everything is great');
});

setTimeout(() => { console.log(123) }, 2000);
// Uncaught (in promise) ReferenceError: x is not defined
// 123
  • 以上代码中,someAsyncThing函数中会出现一个变量为定义的错误,然而因为错误发生在promise对象中,这个错误不会被监听到,promise之后的代码也会继续执行
  • 也就是说promise内部的错误不会影响promise外部的代码
  • 要想监听这个错误可使用node的unhandledRejection事件
  • unhandledRejection事件有两个参数
    • 第一个为错误对象
    • 第二个为报错的Promise实例
process.on('unhandledRejection',function (err, p) {
    throw err;
});

Promise.resolve

有时需要将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。

Promise.resolve一般有四种用法

  • 参数是Promise实例,将直接返回这个实例
  • 参数是个thenable对象,(thenable对象指的是具有then方法的对象,代码如下),会将这个对象转为 Promise 对象然后立即执行它的then方法
let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};
  • 如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个状态为resolved的新 Promise 对象。
const jsPromise = Promise.resolve($.ajax('/whatever.json'));
  • Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。

done()

Promise 对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为 Promise 内部的错误不会冒泡到全局)。因此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。

  • 代码示例:
asyncFunc()
  .then(f1)
  .catch(r1)
  .then(f2)
  .done();
  • 代码实现
Promise.prototype.done = function (onFulfilled, onRejected) {
  this.then(onFulfilled, onRejected)
    .catch(function (reason) {
      // 抛出一个全局错误
      setTimeout(() => { throw reason }, 0);
    });
};

done都会捕捉到任何可能出现的错误,并向全局抛出。

finally()

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。只要proise对象出现最后状态,finally方法就一定会执行。
类似于一个函数的回调。

  • 代码示例
server.listen(0)
  .then(function () {
    // run test
  })
  .finally(server.stop);
  • 代码实现
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 })
  );
};

END

你可能感兴趣的:(异步)