js中promise的then、catch、finally总结

9,388 阅读4分钟

then

最重要,最基本的是then

promise.then(
    function(result) { /* handle a successful result */ },
    function(error) { /* handle an error */ }
);

then的第一个参数是一个函数,它在promise被解析时运行,并接收结果。
then的第二个参数是一个函数,当promise被拒绝时运行,并接收错误。
如果我们只对成功完成感兴趣,那么我们只能为.then提供一个函数参数:

let promise = new Promise(resolve => {
    setTimeout(() => resolve("done!"), 1000);
});
promise.then(alert); // shows "done!" after 1 second

catch

如果我们只对错误感兴趣,那么可以使用null作为第一个参数:.then(null, errorHandlingFunction)。或者我们可以使用.catch(errorHandlingFunction),两者完全相同:

let promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("Whoops!")), 1000);
});
 
// .catch(f) is the same as promise.then(null, f)
promise.catch(alert); // shows "Error: Whoops!" after 1 second

调用.catch(f)完全是对.then(null, f)的模拟,它只是一个简写。

finally

  1. finally 方法用来指定在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行的回调函数。这样可以避免同样的语句需要在 then() 和 catch() 中都要写一次的情况。
    如果你想在 promise 执行完毕后无论其结果怎样都做一些处理或清理时,finally() 方法可能是有用的。
  2. finally 方法的回调函数不接受任何参数,这意味着没有办法知道前面的 Promise 状态到底是 fulfilled 还是 rejected。
    这表明,finally 仅用于无论最终结果如何都要执行的情况,而不能依赖 Promise 执行结果。
  3. finally 方法本身无异常抛出的情况下,总是会返回原来的 Promise 对象值;若抛出异常,则返回异常的 Promise 对象。

总结

  1. Promise 的状态一经改变就不能再改变,也就是说一个Promise实例执行后只有一个状态,要么是resolve, 要么是reject 。resolve或reject后遇到reject或resolve会忽略该代码不执行。但是其他代码仍然会执行
var promise = new Promise((resolve, reject) => {
  resolve("success1");
  console.log('123');
  reject("error");
  console.log('456');
  resolve("success2");
});

promise
.then(res => {
    console.log("then: ", res);
  }).catch(err => {
    console.log("catch: ", err);
  })
//123
//456
//then: success1
  1. then 、 catch 、 finally 都会返回一个新的 promise, 所以可以链式调用。

Promise中,返回任意一个非 promise 的值都会被包裹成 promise 对象,

例如 return 'hehe' 会被包装为return Promise.resolve('hehe')

return 的值只会往下传给 then,无论中间是否有catch 或者 finally。

var promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success1");
  }, 1000)
});

promise
.then(res => {
    console.log("then: ", res);
    return 'bibi';
  }).catch(err => {
    console.log("catch: ", err);
    return 'err';
  }).finally((fin)=> {
    console.log(fin);
    console.log('final');
    return 'haha';
  }).then((res) => {
    console.log(res);
    console.log('final-after')
  }).then((res) => {
    console.log(res);
    console.log('final-after2')
  })
//then: success1
//undefined
//final
//bibi
//final-after
//undefined
//final-after2
  1. catch 可以捕捉上层错误,但是对下层错误是捕捉不到的。
var promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("error");
  }, 1000)
});

promise
.then(res => {
    console.log("then: ", res);
    return 'bibi';
  }).catch(err => {
    console.log("catch: ", err);
    return 'err'; // 这里返回了一个 Promise
  }).then((res)=> { // 继续执行
    console.log('then2', res);
    return Promise.reject('error2');
  }).catch((err) => { //捕捉上层错误,可以隔层捕捉,但是捕捉过的错误不能再捕捉
    console.log('catch2', err);
  })
//catch: error
//then2 err
//catch2 error2
  1. Promise 的 .then 或者 .catch 可以被调用多次, 但如果Promise内部的状态一经改变,并且有了一个值,那么后续每次调用.then或者.catch的时候都会直接拿到该值。
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('timer')
    resolve('success')
  }, 1000)
})
const start = Date.now();
promise.then(res => {
  console.log(res, Date.now() - start)
})
promise.then(res => {
  console.log(res, Date.now() - start)
})
 
//'timer'
//'success' 1001
//'success' 1002
// Promise 的 .then 或者 .catch 可以被调用多次,但这里 Promise 构造函数只执行一次。
// 或者说 promise 内部状态一经改变,并且有了一个值,那么后续每次调用 .then 或者 .catch 都会直接拿到该值。
  1. .then 或者 .catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获。
Promise.resolve().then(() => {
  return new Error('error!!!')
}).then(res => {
  console.log("then: ", res)
}).catch(err => {
  console.log("catch: ", err)
})
 
//"then: " "Error: error!!!"
 
// 这验证了第4点和第6点,返回任意一个非 promise 的值都会被包裹成 promise 对象,
// 因此这里的return new Error('error!!!')也被包裹成了return Promise.resolve(new Error('error!!!'))。

当然如果你抛出一个错误的话,可以用下面的任意一种:

return Promise.reject(new Error('error!!!'));
// or
throw new Error('error!!!')
  1. .then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环。.then 或者 .catch 的参数期望是函数,传入非函数则会发生值透传。

Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .then(console.log)
 
// 1
// 第一个then和第二个then中传入的都不是函数,一个是数字类型,一个是对象类型
// 因此发生了透传,将resolve(1) 的值直接传到最后一个then里。

参考:blog.csdn.net/qq_38211541…