了解promise

Promises

从 ECMAScript 6 开始,JavaScript 增加了对 Promise 对象的支持,它允许你对延时和异步操作流进行控制。

Promise 对象有以下几种状态:

  • pending:初始的状态,即正在执行,不处于 fulfilled 或 rejected 状态。
  • fulfilled:成功的完成了操作。
  • rejected:失败,没有完成操作。

因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回的是 promise, 所以它们可以被链式调用。

promise

Promise的链式调用

我们可以用 promise.then(),promise.catch() 和 promise.finally() 这些方法将进一步的操作与一个变为已敲定状态的 promise 关联起来。这些方法还会返回一个新生成的 promise 对象,这个对象可以被非强制性的用来做链式调用,就像这样:

const myPromise =
  (new Promise(myExecutorFunc))
  .then(handleFulfilledA,handleRejectedA)
  .then(handleFulfilledB,handleRejectedB)
  .then(handleFulfilledC,handleRejectedC);

// 或者,这样可能会更好...

const myPromise =
  (new Promise(myExecutorFunc))
  .then(handleFulfilledA)
  .then(handleFulfilledB)
  .then(handleFulfilledC)
  .catch(handleRejectedAny);
复制代码

链式调用中的 promise 们就像俄罗斯套娃一样,是嵌套起来的,但又像是一个栈,每个都必须从顶端被弹出。链式调用中的第一个 promise 是嵌套最深的一个,也将是第一个被弹出的。

(promise D, (promise C, (promise B, (promise A) ) ) )
复制代码

静态方法

Promise.all(iterable)

这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(可以参考jQuery.when方法—译者注)

Promise.allSettled(iterable)

等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))。
返回一个promise,该promise在所有promise完成后完成。并带有一个对象数组,每个对象对应每个promise的结果。

Promise.any(iterable)

接收一个Promise对象的集合,当其中的一个 promise 成功,就返回那个成功的promise的值。

Promise.race(iterable)

当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。

Promise.reject(reason)

返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法

Promise.resolve(value)

返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果您不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。

方法

Promise.prototype.catch(onRejected)

添加一个拒绝(rejection) 回调到当前 promise, 返回一个新的promise。当这个回调函数被调用,新 promise 将以它的返回值来resolve,否则如果当前promise 进入fulfilled状态,则以当前promise的完成结果作为新promise的完成结果.

Promise.prototype.then(onFulfilled, onRejected)

添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.

Promise.prototype.finally(onFinally)

添加一个事件处理回调于当前promise对象,并且在原promise对象解析完毕后,返回一个新的promise对象。回调会在当前promise运行完毕后被调用,无论当前promise的状态是完成(fulfilled)还是失败(rejected)

执行catch(链式操作中抛出一个失败)例子:

new Promise((resolve, reject) => {
    console.log('初始化');

    resolve();
})
.then(() => {
    throw new Error('有哪里不对了');

    console.log('执行「这个」”');
})
.catch(() => {
    console.log('执行「那个」');
})
.then(() => {
    console.log('执行「这个」,无论前面发生了什么');
});
复制代码

输出结果如下:

初始化
执行“那个”
执行“这个”,无论前面发生了什么
复制代码

示例

本例展示了 Promise 的一些机制。 testPromise() 方法在每次点击 按钮时被调用,该方法会创建一个promise 对象,使用 window.setTimeout() 让Promise等待 1-3 秒不等的时间来填充数据(通过Math.random()方法)。

Promise 的值的填充过程都被日志记录(logged)下来,这些日志信息展示了方法中的同步代码和异步代码是如何通过Promise完成解耦的。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #log{
      border: 1px solid #ddd;
    }
  </style>
</head>
<body>
    <div id="log"></div>
    <div><button onclick="testPromise()">点击</button></div>
</body>
<script>
  var promiseCount = 0;
  
  function testPromise() {
      let thisPromiseCount = ++promiseCount;
  
      let log = document.getElementById('log');
      log.insertAdjacentHTML('beforeend', thisPromiseCount +
          ') 开始 (<small>同步代码开始</small>)<br/>');
  
      // 新构建一个 Promise 实例:使用Promise实现每过一段时间给计数器加一的过程,每段时间间隔为1~3秒不等
      let p1 = new Promise(
          // resolver 函数在 Promise 成功或失败时都可能被调用
         (resolve, reject) => {
              log.insertAdjacentHTML('beforeend', thisPromiseCount +
                  ') Promise 开始 (<small>异步代码开始</small>)<br/>');
              // 创建一个异步调用
              window.setTimeout(
                  function() {
                      // 填充 Promise
                      resolve(thisPromiseCount);
                  }, Math.random() * 2000 + 1000);
          }
      );
  
      // Promise 不论成功或失败都会调用 then
      // catch() 只有当 promise 失败时才会调用
      p1.then(
          // 记录填充值
          function(val) {
              log.insertAdjacentHTML('beforeend', val +
                  ') Promise 已填充完毕 (<small>异步代码结束</small>)<br/>');
          })
      .catch(
          // 记录失败原因
         (reason) => {
              console.log('处理失败的 promise ('+reason+')');
          });
  
      log.insertAdjacentHTML('beforeend', thisPromiseCount +
          ') Promise made (<small>同步代码结束</small>)<br/>');
  }
  </script>
</html>
复制代码

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享