zoukankan      html  css  js  c++  java
  • ES6系列 (04):Promise对象

    状态

    Promise对象有三种状态:

    • pending: 进行中
    • fulfilled: 已成功
    • rejected: 已失败

    resolve 函数:会由 pending-> fulfilled, 状态凝固不会再次改变

    reject 函数:会由 pending-> rejected, 状态凝固不会再次改变

    创建一个Promise实例

    Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由 JavaScript 引擎提供。

    function getNumber(){
        const promise = new Promise((resolve, reject) => {
            //做一些异步操作
            setTimeout(function(){
                var num = Math.ceil(Math.random()*10); //ceil对num进行上舍入  生成1-10的随机数
                if(num<=5){
                   return resolve(num);
                }
                else{
                  return reject('数字太大了');
                }
            }, 2000);
        });
        return promise;            
    }
    

    调用resolvereject并不会终结 Promise 的参数函数的执行。如果不想执行后续代码,我们可以在resolvereject前面加上return语句。

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

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

    Promise常用方法

    Promise.then()

    then方法可以接受两个参数,第一个对应fulfilled状态的回调函数,第二个对应rejected状态的回调函数。第二个参数是可选的,不建议使用,最好使用catch方法

    thencatch()方法返回的是一个Promise实例,存在以下三种情况

    • 当返回非Promise对象的值时,thencatch都生成一个状态为fulfilled的Promise对象,并把该返回值传入Promise链的下一环节
    • 当返回值为Promise对象时,生成的Promise对象的状态由被返回的Promise对象决定,传入Promise链下一环节的值也由这个被返回的Promise决定
    • 当Promise的回调函数中抛出错误时,thencatch都生成一个状态为rejected的Promise对象,并把抛出的错误对象传入Promise链的下一环节。
    getNumber().then(
        function(data){
            console.log('resolved');
            console.log(data);
        }, 
        function(reason){
            console.log('rejected');
            console.log(reason);
        }
    );
    

    Promise.catch()

    catch()方法效果和写在then的第二个参数里面一样,对应rejected状态的回调函数。不过它还有另外一个作用:在执行fulfilled状态的回调函数(也就是上面then中的第一个参数)时,如果抛出异常了,那么并不会报错卡死js,而是会进到catch方法中。

    catch()方法返回的还是一个 Promise实例,因此后面还可以接着调用then()方法。

    getNumber().then(function(data){
        console.log('resolved');
        console.log(data);
        console.log(somedata); //此处的somedata未定义 ReferenceError: somedata is not defined
    })
    .catch(function(reason){
        console.log('rejected');
        console.log(reason);
    });
    

    Promise.finally()

    不管promise最后的状态,在执行完thencatch指定的回调函数以后,都会执行finally方法指定的回调函数。

    finally方法的回调函数不接受任何参数。

    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});
    

    Promise.all()

    Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

    const p = Promise.all([p1, p2, p3]);
    

    上面代码中,Promise.all()方法接受一个数组作为参数,p1p2p3都是 Promise 实例,如果不是,就会先调用Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

    p的状态由p1p2p3决定,分成两种情况。

    • 只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

    • 只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

    注意:

    Promise.all 方法会按照并行的模式,将所有请求一次性全部发送出去,然后等待接收到全部结果后,按照顺序打印出来。所以,该方法并不适用于继发执行请求

    Promise.resolve()

    Promise.resolve()方法会将现有对象转为 Promise 对象,该实例的状态为fulfilled

    Promise.resolve('burc')
    // 等同于
    new Promise(resolve => resolve('burc'))
    

    需要注意的是,立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。

    setTimeout(function () {
      console.log('three');
    }, 0);
    
    Promise.resolve('burc').then(function () {
      console.log('two');
    });
    
    console.log('one');
    
    // one
    // two
    // three
    

    上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。

    Promise.reject()

    Promise.reject(reason)方法也会返回一个新的 Promise实例,该实例的状态为rejected

    const p = Promise.reject('出错了');
    // 等同于
    const p = new Promise((resolve, reject) => reject('出错了'))
    

    Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。

    Promise.reject('出错了').catch(e => {
      console.log(e === '出错了')
    })
    // true
    

    链式调用

    Promise 是异步编程的一种解决方案,它的链式调用成功解决了传统的回调地狱难题,but,公司里的老代码用promise也写出了回调地狱,这很没有精神,下面是代码示例,论如何正确使用promise

    promise错误用法 VS promise正确用法

    参考文档

    阮一峰 Promise对象

    人间不正经生活手册
  • 相关阅读:
    满血复活
    绝望,绝望、希望
    认真生活的态度
    星期一
    户外穿越
    认真准备
    早点休息
    LeetCode OJ
    LeetCode OJ
    LeetCode OJ
  • 原文地址:https://www.cnblogs.com/burc/p/14124655.html
Copyright © 2011-2022 走看看