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

Promise 对象promise

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

目前 JavaScript 原生支持 Promise 对象异步

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

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

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

 

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

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

 

    • 不只改善了可读性,并且对于多层嵌套的回调函数尤为方便。
      • 传统的写法可能须要把 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());
            }
        });
        // 该函数的两个参数分别是 和 。它们是两个函数,由 JavaScript 引擎提供,不用本身实现
        resolvereject

         

      • resolve() 函数设计

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

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

      • 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)在下一轮事件循环开始时执行

相关文章
相关标签/搜索