Promise对象一些零碎知识点记录

  • Promise对象实例的resolve函数的参数除了正常的值外,还可能是另一个promise实例,如:

    var p1 = new Promise((resolve,reject) => {
        //...
    })
    var p2 = new Promise((resolve, reject) => {
        resolve(p1)
    })
    

    由于 **p1**和 **p2**都是promise实例,但是p2的resolve将p1作为了参数,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

    const p1 = new Promise(function (resolve, reject) {
      setTimeout(() => reject(new Error('fail')), 3000)
    })
    
    const p2 = new Promise(function (resolve, reject) {
      setTimeout(() => resolve(p1), 1000)
    })
    
    p2
      .then(result => console.log(result))
      .catch(error => console.log(error))
    // Error: fail
    

    上面代码中,p1是一个 Promise,3 秒之后变为rejectedp2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。

  • 调用resolvereject并不会终结 Promise 的参数函数的执行。

    new Promise((resolve, reject) => {
      resolve(1);
      console.log(2);
    }).then(r => {
      console.log(r);
    });
    // 2
    // 1
    

    上面代码中,调用resolve(1)以后,后面的console.log(2)还是会执行,并且会首先打印出来。这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

    **注意:**有种情况除外,如下:

    new Promise((resolve, reject) => {
      resolve(1);
      throw new Error('执行出错了')
    }).then(r => {
      console.log(r);
    }).catch(err => {
      console.log(err) 
    })
    // 1
    // "执行出错了"不会被打印出来,因为promise中状态一旦改变,就不会再变
    
  • promise.prototype.then()promise.prototype.catch()中返回的都是promise实例,从而保证了promise的链式调用,如:

    new Promise((resolve, reject) => {
        resolve(2)
    }).then(res => {
        console.log('我被执行了') 
    	// 这时候会返回一个新的promise对象    
    }).then(res => {
        console.log('我也执行了')
    })
    // 我被执行了
    // 我也执行了
    
  • 抛出异常的等同写法

    // 写法一
    const promise = new Promise(function(resolve, reject) {
      try {
        throw new Error('test');
      } catch(e) {
        reject(e);
      }
    });
    promise.catch(function(error) {
      console.log(error);
    });
    
    // 写法二
    const promise = new Promise(function(resolve, reject) {
      reject(new Error('test'));
    });
    promise.catch(function(error) {
      console.log(error);
    });
    
  • 跟传统的try/catch代码块不同的是,如果没有使用catch()方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。

    const someAsyncThing = function() {
      return new Promise(function(resolve, reject) {
        // 下面一行会报错,因为x没有声明
        resolve(x + 2);
      });
    };
    
    someAsyncThing().then(function() {
      console.log('everything is great');
    });
    
    setTimeout(() => { console.log(123) }, 2000);
    // Uncaught (in promise) ReferenceError: x is not defined
    // 123
    

    上面代码中,someAsyncThing()函数产生的 Promise 对象,内部有语法错误。浏览器运行到这一行,会打印出错误提示ReferenceError: x is not defined,但是不会退出进程、终止脚本执行,2 秒之后还是会输出123。这就是说,Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。

    const promise = new Promise(function (resolve, reject) {
      resolve('ok');
      setTimeout(function () { throw new Error('test') }, 0)
    });
    promise.then(function (value) { console.log(value) });
    // ok
    // Uncaught Error: test
    

    上面代码中,Promise 指定在下一轮“事件循环”再抛出错误。到了那个时候,Promise 的运行已经结束了,所以这个错误是在 Promise 函数体外抛出的,会冒泡到最外层,成了未捕获的错误。

  • Promisse.prototype.finally的实现方式,本质上是Promise.then的特殊实现方式,finally方法总是会返回原来的值。

    //1.等价形式
    promise
    .finally(() => { /*语句*/ });
    // 等同于
    promise.then(result => {/*语句*/ return result;},error => {/*语句*/  throw error;});
    
    //2.实现方式
    Promise.prototype.finally = function (callback) {
    let P = this.constructor;
      return this.then(
        value  => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason })
      );
    };
    
  • Promise.all的特点

    // 情况一:
    const p1 = new Promise((resolve,reject) => {
      setTimeout(() => {
            resolve(2)
        }, 1000)
    })
    const p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('出错了')
        }, 1000)
    })
    const promiseArr = Promise.all([p1, p2]).then(res => {
        console.log(res)
    }).catch(err => {
        console.log(err)
    })
    
    注:针对这种情况,只有p1和p2都fullfilled,promiseArr才会fullfilled,执行后面的then方法,
    当p1和p2中有任何一个出错,都会进入catch中的方法。第一个被reject的返回值将执行catch函数,
    
    // 情况二:
    const p1 = new Promise((resolve,reject) => {
        setTimeout(() => {
            resolve(2)
        }, 1000)
    }).catch(err => {
        console.log(err)
    })
    const p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('出错了')
        }, 1000)
    }).catch(err => {
        console.log(err)
    })
    const promiseArr = Promise.all([p1, p2]).then(res => {
        console.log(res)
    }).catch(err => {
        console.log(err)
    })
    
    注:针对这种情况,由于p1和p2都有自己的catch方法,p2的reject函数将由自己的catch方法捕获,catch函
    数又会抛出一个新的promise实例,所以promiseArr始终执行后面的then函数,而不会执行catch方法
    
  • Promise.race和Promise.allsettled(ES2020引入)和Promise.any(ES2021引入)的区别

    const a1 = Promise.race([p1, p2, p3]);
    //a1 是一个promise实例,当p1、p2、p3中任何一个状态发生改变,a1的状态就跟着发生改变
    const a2 = Promise.allsettled([p1, p2, p3]);
    //a2 同样也是一个promise实例,只有当p1,p2,p3全部返回结果,a2的状态才会发生改变,a2始终是fullfilled,也就是始终执行a2.then(()=>{})回调函数,不会被reject,从而执行catch函数,p1,p2,p3是fuillfilled还是reject不对a2造成影响
    const a3 = Promise.any([p1, p2, p3]);
    //a3 同样也是一个promise实例,跟Promise.race()相似,只要p1,p2,p3中任何一个fullfilled,a3就会fullfilled,区别在于,Promise.race()只有当p1,p2,p3全部都rejected,a3才会rejected
    
  • Promise.resolve和Promise.reject()

    Promise.resolve和Promise.reject可以快速的生成一个resolved的Promise对象和rejected的Promise对象

    Promise.resolve('foo')
    // 等价于
    new Promise(resolve => resolve('foo'))
    
  • Promise.resolve()方法的参数的几种情况

    // 情况一:参数本身就是一个Promise对象,则Promise.resolve()执行后,不做任何修改,原封不动的返回这个Promise对象
    var p = new Promise((resolve,reject) => {
       console.log(5)
    })
    var a = Promise.resolve(p)
    console.log(a=== p) // true
    
    // 情况二:参数是一个thenable对象,所谓thenable对象是指具有then方法的对象,Promise.resolve执行后会将这个对象转为Promise对象,并立即执行这个对象的then方法,
    var thenable = {
        then: (resolve, reject) => resolve(2)
    }
    var p1 = Promise.resolve(thenable).then(res => {
        console.log(res) // 打印2
    })
    
    //情况三:参数是一个不具有then方法的的对象,或者根本不是对象,Promise.then()将返回一个新的Prmoise对象,状态为resolved,同时将resolve中的参数传递给回调函数
    var p1 = new Promise('我是是一个字符串')
    var p = Promise.resolve(p1).then(res => {
        console.log(res) // 我是一个字符串
    })
    
    // 情况四:不具有任何参数,这种情况可以看出情况三的特例子,这时候直接返回一个Promise对象,状态为resolved,所以想直接生成一个Promise对象,可以直接使用Promise.resolve()快速生成是一个Promise对象
    
    

    注意:立即resolve()的Promise对象,是在本轮事件循环的结束时执行,而不是在下一轮事件循环的开始时

    setTimeout(() => {
        console.log('我也执行了')
    })
    const p = Promise.resolve().then(() => {
       console.log('我先执行')
    })
    
    // 我先执行
    // 我也执行了
    
  • Promise.try()的用法(详见:[ECMAScript 6 入门](https://es6.ruanyifeng.com/)

参考:
ECMAScript 6 入门
文章主要参考阮一峰ES6教程的Promise相关知识点,对部分内容进行了总结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值