promise总结

113 阅读5分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);//只有调用了resolve函数后,promise的状态才会由‘未完成’变成‘成功’
  } else {
    reject(error);
  }
});
promise.then(function(){
//当promise的状态变为成功时调用,如果没有调用resolve函数,promise的状态不是成功,此函数就不会调用
},function(){
//当promise的状态变为失败时调用
})
  • resolve函数执行后,将Promise的状态从“未完成”变为“成功”,在异步操作成功后调用,并将结果作为参数传递出去
  • reject函数执行后,将Promise的状态从“未完成”变为“失败”,在异步操作失败后调用,并将错误作为参数传递出去
  • .then和.catch都会返回一个新的promise,不管.then和.catch中是否有return,都会返回一个新的promise,如果return的是一个promise,则不做处理,如果返回的是一个非promise的值会被包裹为promise对象,例如return 2会被包装为return Promise.resolve(2),其实链式调用的本质就是因为他then和catch之后返回的是promise
let pr = Promise.resolve("p11").then(function (data) {
    console.log(data)//data12
    // return p2
},function (err) {
    console.log(err)
})
    .then(function (data2) {
        console.log(data2)
        return 2
    })
    .then(function (data3) {
        console.log(data3)
    })
    // p11 undefined 2
  • promise的状态一经改变就不能再改变
const promise = new Promise((resolve, reject) => {
  resolve("success1");
  reject("error");
  resolve("success2");
});
promise
.then(res => {
    console.log("then: ", res);
  }).catch(err => {
    console.log("catch: ", err);
  })
//最后结果是success1,promise的状态一经改变就不会再改变
  • .then和.catch可以被调用多次,但是Promise构造函数只执行一次,或者说promise的内部状态一经改变,并且有了一个值,那么后续多次调用.then或者.catch都会直接拿到该值
let pr = Promise.resolve(Date.now()).then(function (data) {
    console.log(data)//data12
    return data
},function (err) {
    console.log(err)
})
   pr.then(function (data2) {
        console.log(data2)
    })
    pr.then(function (data3) {
        console.log(data3)
    })
    //打印出来的数据都是一样的
  • .then或者.catch中return一个error对象并不会抛出错误,不会被后续catch捕获,return new Error('error!!!')也被包裹成了return Promise.resolve(new Error('error!!!'))。 想抛出错误的话,用下面:
return Promise.reject(new Error('error!!!'));
// or
throw new Error('error!!!')
  • .then或者.catch不能return promise本身,否则会造成死循环
  • finally方法的回调函数不接受任何参数,finally中不知道promise的状态是失败还是成功,没有办法获得此时promise的执行结果,finally会返回一个promise,特殊的是返回的promise是上一个promise的值包装成的新promise,不管finally中return什么
var p1 = new Promise(function(resolve, reject) {
    reject(1)
})
    .then(
        res => {
            console.log(res)
            return 2
        },
        err => {
            console.log(err)
            return 344
        }
    )
    .catch(err => {
        console.log(err)
        return 4
    })
    .finally(res => {
    //finally回调函数没有任何参数
        console.log(res)//undefined
        return 5//finally返回的promise是上一个promise的值包装的新promise,所以这里return不管返回什么都不生效
    })
    .then(
        res => console.log(res),
        err => console.log(err)
    )
    //1 undefined 344
// promise
//! Promise一般来讲是一个对象,.then方法是promise对象对一个方法

/**
 * Promise构造函数接收一个函数A作为参数,函数A有2个参数,resolve和reject,
 * 调用resolve这个函数,标记为成功,调用reject这个函数,标记为失败;
 * resolve和reject在调用时,可以传递数据,这个数据会被传递给成功或失败的回调函数中
 * 在这个函数A中可以执行异步操作,在这个函数中执行完成异步操作之前,
 * 并不是调用用户提供的回调函数(不关心回调到底是什么),而是在这个函数中,异步操作完成后
 * 修改当前promise的状态
 *
 */

/**
 * Promise的状态
 * pendding:挂起,当前promise正在执行任务
 * fullfilled:完成任务,成功状态
 * rejected:完成任务,失败状态
 * */

/**
 * Promise对象的.then方法接收的成功的回调函数会在promise对象处于成功(fullfilled)状态下自动执行
 * Promise对象的.then方法接收到的失败的回调函数会promise对象处于失败(rejected)状态下自动执行
 * then方法的返回值有两种:
 * 1、promise对象:
 * 调用下一个then,链式调用;
.then 在链式调用时,会等其前一个 then 中的回调函数执行完毕,并且返回成功状态的 promise,才会执行下一个 then 的回调函数,而且 .then 方法的参数就是上一个 .then 方法中 resolve 的参数。

所以链式调用比较常用的一个场景就是,当下一个操作依赖于上一个操作的结果或状态的时候,可以很方便地通过 .then 方法的参数来传递数据。
 * 2、普通值:
 * 将该普通值传递给下一个then,作为then中回调函数的参数
 * */
var p =new Promise(function (resolve,reject) {
    setTimeout(function () {
        //!resolve将promise的状态置为成功fullfielled
        resolve("data12")
    },1000)
})

p.then(function (data) {
    //!data为resolve函数传递的数据
    //! 成功回调,会在promise的状态变为fullfilled成功时自动执行
    console.log("成功回调")
    console.log(data)//data12
    return data
},function (err) {
    //! err为reject函数传递的数据
    //!失败回调,会在promise的状态变为rejected失败时自动执行
    console.log("失败回调")
    console.log(err)
})
    .then(function (data2) {
        console.log(data2)
        return data2
    })
    .then(function (data3) {
        console.log(data3)
    })


//* 写法1
p.then(function (data) {
    console.log("成功的回调")
},function (err) {
    console.log("失败的回调")
})
//* 写法2
p.then(function (data) {
    console.log("成功的回调")
})
    .catch(function () {
    console.log("失败的回调")
})
//* 写法1和写法2是效果一样的,不过写法2在出现代码异常的时候不会报错卡死,而是进入catch中


关于promise的面试题

  • Promise.all中如果有一个抛出异常了会如何处理

all和race传入的数组中如果有任务抛出异常,那么只有最先抛出异常的错误会被捕获,并且是被then的第二个参数或者后面的catch捕获,但不会影响数组中其他异步任务的执行

  • Promise为什么能链式调用

由于then,catch,finally方法会返回一个新的promise,所以可以链式调用

  • Promise.all是并发的还是串行的

并发的,不过Promise.all().then()结果中数组的顺序和Promise.all()接收到的数组顺序一致