• (84)Wangdao.com第十八天_JavaScript Promise 对象


    Promise 对象

    是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。

    目前 JavaScript 原生支持 Promise 对象

    它起到代理作用(proxy),充当异步操作回调函数之间的中介,使得异步操作具备同步操作的接口。

    Promise 可以让异步操作写起来,就像在写同步操作的流程,而不必一层层地嵌套回调函数。

    • Promise 是一个对象,也是一个构造函数
      function f1(resolve, reject) {
        // 异步代码...
      }
      
      var p1 = new Promise(f1);
      // Promise 构造函数接受一个回调函数 f1() 作为参数,f1() 里面是异步操作的代码。然后,返回的p1 就是一个 Promise 实例

     

    • Promise 的设计思想
      • 所有异步任务都返回一个 Promise 实例。
        • Promise 实例有一个 then 方法,用来指定下一步的回调函数。
          var p1 = new Promise(f1);
          p1.then(f2);

          f1() 的异步操作执行完成,就会执行 f2()

     

      • 不仅改善了可读性,而且对于多层嵌套的回调函数尤其方便。
        • 传统的写法可能需要把 f2() 作为回调函数传入 f1(),比如写成f1(f2),异步操作完成后,在 f1() 内部调用 f2()。
        • 而 Promise 使得 f1() 和 f2() 变成了链式写法。
          // 传统写法
          step1(function (value1) {
              step2(value1, function(value2) {
                  step3(value2, function(value3) {
                      step4(value3, function(value4) {
                          // ...
                      });
                  });
              });
          });
          
          // Promise 的写法
          (new Promise(step1)).then(step2).then(step3).then(step4);

     

    • 通过自身的状态,来控制异步操作。
    • Promise 实例具有三种状态
        • 异步操作未完成(pending)
        • 异步操作成功(fulfilled)
        • 异步操作失败(rejected)
      • 上面三种状态里面,fulfilled 和 rejected合在一起称为 resolved(已定型)。
      • 这三种的状态的变化途径只有两种:
        • 从 “未完成” 到 “成功”
        • 从 “未完成” 到 “失败”
      • 它的英语意思是“承诺”,一旦承诺成效,就不得再改变了。
      • 一旦状态发生变化,就凝固了,不会再有新的状态变化。
      • 这也意味着,Promise 实例的状态变化只可能发生一次。

     

    • Promise 构造函数
      • JavaScript 提供原生的 Promise 构造函数,用来生成 Promise 实例
        • var promise = new Promise(function (resolve, reject) {
              // ...
          
              if (/* 异步操作成功 */){
                  resolve(value);
              } else { /* 异步操作失败 */
                  reject(new Error());
              }
          });
          // 该函数的两个参数分别是 resolve reject 。它们是两个函数,由 JavaScript 引擎提供,不用自己实现
        • resolve() 函数

          • 作用是,将Promise实例的状态从“未完成”变为“成功”(即从pending变为fulfilled)

          • 在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。

        • reject函数

          • 作用是,将Promise实例的状态从“未完成”变为“失败”(即从pending变为rejected)

          • 在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

      • 实例
        • function timeout(ms) {
              return new Promise((resolve, reject) => {
                  setTimeout(resolve, ms, 'done');
              });
          }
          
          timeout(100)

          上面代码中,timeout(100) 返回一个 Promise 实例。100毫秒以后,该实例的状态会变为 fulfilled

     

    • Promise.prototype.then() 
      • Promise 实例的then方法,用来添加回调函数
      • 可以接受两个回调函数,一旦状态改变,就调用相应的回调函数。
        • 第一个是异步操作成功时(变为fulfilled状态)的回调函数
        • 第二个是异步操作失败(变为rejected)时的回调函数(该参数可以省略)。
          • var p1 = new Promise(function (resolve, reject) {
                resolve('成功');
            });
            p1.then(console.log, console.error);    // "成功"
            
            
            var p2 = new Promise(function (resolve, reject) {
                reject(new Error('失败'));
            });
            p2.then(console.log, console.error);    // Error: 失败
          • p1 和 p2 都是Promise 实例,它们的 then() 方法绑定两个回调函数:成功时的回调函数 console.log,失败时的回调函数 console.error(可以省略)。

          • p1 的状态变为成功,p2 的状态变为失败

          • 对应的回调函数会收到异步操作传回的值,然后在控制台输出

     

    • 实例:图片加载
      • 使用 Promise 完成图片的加载
        • var preloadImage = function (path) {
              return new Promise(function (resolve, reject) {
                  var image = new Image();
                  image.onload  = resolve;
                  image.onerror = reject;
                  image.src = path;
              });
          };
        • 调用

          preloadImage('https://example.com/my.jpg')
              .then(function (e) { document.body.append(e.target) })
              .then(function () { console.log('加载成功') })

     

    • 强大之处:
      • 让回调函数变成了规范的链式写法,程序流程可以看得很清楚。
      • 它有一整套接口,可以实现许多强大的功能,
        • 比如同时执行多个异步操作,等到它们的状态都改变以后,再执行一个回调函数
        • 再比如,为多个回调函数中抛出的错误,统一指定处理方法等等。
      • 它的状态一旦改变,无论何时查询,都能得到这个状态。
        • 这意味着,无论何时为 Promise 实例添加回调函数,该函数都能正确执行。
        • 所以,你不用担心是否错过了某个事件或信号。
        • 如果是传统写法,通过监听事件来执行回调函数,一旦错过了事件,再添加回调函数是不会执行的。

     

    • 微任务(Microtask)
      • Promise 的回调函数属于异步任务,会在同步任务之后执行。
        • new Promise(function (resolve, reject) {
              resolve(1);
          }).then(console.log);
          
          console.log(2);
          // 2
          // 1
          // 上面代码会先输出 2,再输出 1 。
          // 因为 console.log(2)是同步任务,而 then 的回调函数属于异步任务,一定晚于同步任务执行
      • Promise 的回调函数不是正常的异步任务,而是微任务(microtask)
      • 它们的区别在于
        • 正常任务追加到下一轮事件循环
        • 微任务追加到本轮事件循环
        • 这意味着,微任务的执行时间一定早于正常任务。
      • setTimeout(function() {
            console.log(1);
        }, 0);
        
        new Promise(function (resolve, reject) {
            resolve(2);
        }).then(console.log);
        
        console.log(3);
        // 3
        // 2
        // 1
      • 输出结果是321。这说明 then 的回调函数的执行时间,早于setTimeout(fn, 0)。

      • 因为 then 是本轮事件循环执行,setTimeout(fn, 0)在下一轮事件循环开始时执行

    --------小尾巴 ________一个人欣赏-最后一朵颜色的消逝-忠诚于我的是·一颗叫做野的心.决不受人奴役.怒火中生的那一刻·终将结束...
  • 相关阅读:
    适配器和外观模式
    命令模式
    单件模式
    工厂模式
    装饰者模式
    观察者模式(发布--订阅模式)
    设计模式之策略模式
    C#学习笔记15
    C#学习笔记14
    lucky的时光助理-2017.02
  • 原文地址:https://www.cnblogs.com/tianxiaxuange/p/9815958.html
Copyright © 2020-2023  润新知