欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Promise详解

程序员文章站 2022-03-22 12:10:16
一、简介 Promise,他是一个对象,是用来处理异步操作的,可以让我们写异步调用的时候写起来更加优雅,更加美观便于阅读。顾名思义为承诺、许诺的意思,意思是使用了Promise之后他肯定会给我们答复,无论成功或者失败都会给我们一个答复,所以我们就不用担心他跑了哈哈。所以,Promise有三种状态:p ......

一、简介

  promise,他是一个对象,是用来处理异步操作的,可以让我们写异步调用的时候写起来更加优雅,更加美观便于阅读。顾名思义为承诺、许诺的意思,意思是使用了promise之后他肯定会给我们答复,无论成功或者失败都会给我们一个答复,所以我们就不用担心他跑了哈哈。所以,promise有三种状态:pending(进行中),resolved(完成),rejected(失败)。只有异步返回的结构可以改变其状态。所以,promise的过程一般只有两种:pending->resolved或者pending->rejected。

  状态详解:

(1)promise 从未完成的状态开始,如果成功它将会是完成态,如果失败将会是失败态。
(2)当一个 promise 移动到完成态,所有注册到它的成功回调将被调用,而且会将成功的结果值传给它。另外,任何注册到 promise 的成功回调,将会在它已经完成以后立即被调用。
(3)同样的,当一个 promise 移动到失败态的时候,它调用的是失败回调而不是成功回调。
(4)对包含前进特性的实现来说,promise 在它离开未完成状态以前的任何时刻,都可以更新它的 progress。当 progress 被更新,所有的前进回调(progress callbacks)会被传递以 progress 的值,并被立即调用。前进回调被以不同于成功和失败回调的方式处理;如果你在一个 progress 更新已经发生以后注册了一个前进回调,新的前进回调只会在它被注册以后被已更新的 progress 调用。
(5)注意:只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
 

二、使用promises

1、错误捕获

如果在执行器内部抛出了错误,那么 promise 的拒绝处理函数就会被调用。例如:

let promise = new promise(function(resolve, reject) {
  throw new error("explosion!");
});
promise.catch(function(error) {
  console.log(error.message); // "explosion!"
});

在此代码中,执行器故意抛出了一个错误。此处在每个执行器之内并没有显式的 try-catch
,因此错误就被捕捉并传递给了拒绝处理函数。这个例子等价于:

let promise = new promise(function(resolve, reject) {
    try {
        throw new error("explosion!");
    } catch (ex) {
        reject(ex);
    }
});
promise.catch(function(error) {
    console.log(error.message); // "explosion!"
});        


执行器处理程序捕捉了抛出的任何错误,以简化这种常见处理。但在执行器内抛出的错误仅
当存在拒绝处理函数时才会被报告,否则这个错误就会被隐瞒。

2、创建已决的 promise

基于 promise 执行器行为的动态本质, promise 构造器就是创建未决的 promise 的最好方
式。但若你想让一个 promise 代表一个已知的值,那么安排一个单纯传值给 resolve() 函数
的作业并没有意义。相反,有两种方法可使用指定值来创建已决的 promise 。
使用 promise.resolve()
promise.resolve() 方法接受单个参数并会返回一个处于完成态的 promise 。这意味着没有
任何作业调度会发生,并且你需要向 promise 添加一个或更多的完成处理函数来提取这个参
数值。例如:

let promise = promise.resolve(42);
promise.then(function(value) {
  console.log(value); // 42
});

此代码创建了一个已完成的 promise ,因此完成处理函数就接收到 42 作为 value 参数。若
一个拒绝处理函数被添加到此 promise ,该拒绝处理函数将永不会被调用,因为此 promise
绝不可能再是拒绝态。
使用 promise.reject()
你也可以使用 promise.reject() 方法来创建一个已拒绝的 promise 。此方法像
promise.resolve() 一样工作,区别是被创建的 promise 处于拒绝态,如下:

let promise = promise.reject(42);
promise.catch(function(value) {
  console.log(value); // 42
});

 

3、监视多个 promise

有时你会想监视多个 promise的进程,以便决定下一步行动。 es6 提供了能监视多个 promise 的两个方法:
promise.all() 与 promise.race() 。

promise.all() 方法:

promise.all() 方法接收单个可迭代对象(如数组)作为参数,并返回一个 promise 。这个
可迭代对象的元素都是 promise ,只有在它们都完成后,所返回的 promise 才会被完成。例
如:

let p1 = new promise(function(resolve, reject) {
  resolve(42);
});
let p2 = new promise(function(resolve, reject) {
  resolve(43);
});
let p3 = new promise(function(resolve, reject) {
  resolve(44);
});
let p4 = promise.all([p1, p2, p3]);
p4.then(function(value) {
  console.log(array.isarray(value)); // true
  console.log(value[0]); // 42
  console.log(value[1]); // 43
  console.log(value[2]); // 44
});

此处前面的每个 promise 都用一个数值进行了决议,对 promise.all() 的调用创建了新的
promise p4 ,在 p1 、 p2 与 p3 都被完成后, p4 最终会也被完成。传递给 p4 的完
成处理函数的结果是一个包含每个决议值( 42 、 43 与 44 )的数组,这些值的存储顺序保
持了待决议的 promise 的顺序(与完成的先后顺序无关),因此你可以将结果匹配到每个
promise 。
若传递给 promise.all() 的任意 promise 被拒绝了,那么方法所返回的 promise 就会立刻被
拒绝,而不必等待其他的 promise 结束:

let p1 = new promise(function(resolve, reject) {
  resolve(42);
});
let p2 = new promise(function(resolve, reject) {
  reject(43);
});
let p3 = new promise(function(resolve, reject) {
  resolve(44);
});
let p4 = promise.all([p1, p2, p3]);
p4.catch(function(value) {
  console.log(array.isarray(value)) // false
  console.log(value); // 43
});

在此例中, p2 被使用数值 43 进行了拒绝,则 p4 的拒绝处理函数就立刻被调用,而不会
等待 p1 或 p3 结束执行(它们仍然会各自结束执行,只是 p4 不等它们)。
拒绝处理函数总会接收到单个值,而不是一个数组,该值就是被拒绝的 promise 所返回的拒
绝值。本例中的拒绝处理函数被传入了 43 ,反映了来自 p2 的拒绝。

promise.race() 方法:

promise.race() 提供了监视多个 promise 的一个稍微不同的方法。此方法也接受一个包含需
监视的 promise 的可迭代对象,并返回一个新的 promise ,但一旦来源 promise 中有一个被
解决,所返回的 promise 就会立刻被解决。与等待所有 promise 完成的 promise.all() 方法
不同,在来源 promise 中任意一个被完成时, promise.race() 方法所返回的 promise 就能
作出响应。例如:

let p1 = promise.resolve(42);
let p2 = new promise(function(resolve, reject) {
  resolve(43);
});
let p3 = new promise(function(resolve, reject) {
  resolve(44);
});
let p4 = promise.race([p1, p2, p3]);
p4.then(function(value) {
  console.log(value); // 42
});

在此代码中, p1 被创建为一个已完成的 promise ,而其他的 promise 则需要调度作业。
p4 的完成处理函数被使用数值 42 进行了调用,并忽略了其他的 promise 。传递给
promise.race() 的 promise 确实在进行赛跑,看哪一个首先被解决。若胜出的 promise 是被
完成,则返回的新 promise 也会被完成;而胜出的 promise 若是被拒绝,则新 promise 也会
被拒绝

4、串联 promise

存在多种方式来将 promise 串联在一起,以完成更复杂的异步行为。
每次对 then() 或 catch() 的调用实际上创建并返回了另一个 promise ,仅当前一个
promise 被完成或拒绝时,后一个 promise 才会被决议

在 promise 链中返回值

promise 链的另一重要方面是能从一个 promise 传递数据给下一个 promise 的能力。传递给
执行器中的 resolve() 处理函数的参数,会被传递给对应 promise 的完成处理函数,这点你
前面已看到过了。你可以指定完成处理函数的返回值,以便沿着一个链继续传递数据。例
如:

let p1 = new promise(function(resolve, reject) {
  resolve(42);
});
p1.then(function(value) {
  console.log(value); // "42"
  return value + 1;
}).then(function(value) {
  console.log(value); // "43"
});

p1 的完成处理函数在被执行时返回了 value + 1 。由于 value 的值为 42 (来自执行
器),此完成处理函数就返回了 43 。这个值随后被传递给第二个 promise 的完成处理函数,
并被其输出到控制台。

在 promise 链中返回 promise

从完成或拒绝处理函数中返回一个基本类型值,能够在 promise 之间传递数据,但若你返回
的是一个对象呢?若该对象是一个 promise ,那么需要采取一个额外步骤来决定如何处理。
研究以下例子:

let p1 = new promise(function(resolve, reject) {
  resolve(42);
});
let p2 = new promise(function(resolve, reject) {
  resolve(43);
});
p1.then(function(value) {
  // 第一个完成处理函数
  console.log(value); // 42
  return p2;
}).then(function(value) {
  // 第二个完成处理函数
  console.log(value); // 43
});

在此代码中, p1 安排了一个决议 42 的作业, p1 的完成处理函数返回了一个已处于决议
态的 promise : p2 。由于 p2 已被完成,第二个完成处理函数就被调用了。而若 p2 被
拒绝,会调用拒绝处理函数(如果存在的话),而不调用第二个完成处理函数。