• (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# 反射数据库数据过程中值类型存在DBNull的处理方法 == System.DBNull.Value
    Git 未能顺利结束 (退出码 128)解决办法 git常用命令流程图
    IDEA之The directory xxxxx is under Git, but is not registered in the Settings.
    git push提交成功后如何撤销回退 我是手动修改再提交一次 。。或者IDEA有代码修改历史记录功能 进行回退
    IDEA,发现Project文件目录不见了,只剩External Libraries的原因
    分布式事务 seata
    idea设置类,方法模板 阿里检测
    随笔
    初学一点点空间分解和有理标准型
    Vue2+Cesium1.9+热力图开发笔记
  • 原文地址:https://www.cnblogs.com/tianxiaxuange/p/9815958.html
Copyright © 2020-2023  润新知