Promise链式调用终极答案

236 阅读4分钟

promise链式调用

Promise.resolve().then(function() {
  console.log('promise1'); 
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
}).then(function(value) {
  console.log('promise2');
  console.log(value, 'value');
});

输出结果如下,因为没有return一个promise,所以是value是空的 其实这里then是返回一个promise, 但是promise是要fulfilled才会跑到then里面去的,所以这个then返回的就算是一个fulfilled的promise了

image.png

来看第二种情况

Promise.resolve().then(function() {
  console.log('promise1'); 
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
  return Promise.resolve('我是value');
  // return '我是value'   //  等同于这个效果
}).then(function(value) {
  console.log('promise2');
  console.log(value, 'value');
});

输出结果如下,因为return了一个promise,所以是value是有的

image.png

来看第三种情况,是如果我们是return一个reject的Promise

Promise.resolve().then(function() {
  console.log('promise1'); 
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
  return Promise.reject('我是reject后的value');
}).then(function(value) {
  console.log('promise2');
  console.log(value, 'value');
});

输入结果如下,因为return了一个reject的promise,所以跑不到第二个then里面

image.png

另外看一种情况,就是then里面其实可以接受两个函数,一个是promise resolve会跑进去的函数,就是第一个,一个是promise reject会跑进去的函数,就是第二个

Promise.resolve().then(function() {
  console.log('promise1'); 
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
}, function(){
  console.log('rejectPromise')
}).then(function(value) {
  console.log('promise2');
  console.log(value, 'value');
});

很明显不会打印 rejectPromise

image.png

那什么情况才会跑到第二个函数里面去

Promise.reject().then(function() {
  console.log('promise1'); 
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
}, function(){
  console.log('rejectPromise')
}).then(function(value) {
  console.log('promise2');
  console.log(value, 'value');
});

这里就跑到第二函数里去了,因为promise reject了,因为这里有第二个函数兜住了reject,所以链式调用能继续,如果没有兜住,就不能继续往下走了,会报错,所以reject一定要兜住,如果兜住了,然后then如果没有返回值,绝对是返回一个fulfilled的promise(对比第三种)

image.png

再看catch有什么用

Promise.reject().then(function() {
  console.log('promise1'); 
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
}).then(function(value) {
  console.log('promise2');
  console.log(value, 'value');
});

这里没有第二个参数兜住,所以跑不到第二个then里面去,页面也会报错 这时候我们使用catch

Promise.reject('错').then(function() {
  console.log('promise1'); 
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
}).catch(function(err) {
  console.log('promise2');
  console.log(err, 'err');
});

如果reject,然后没有第二个参数兜住,便会被catch捕获

Promise.reject('错').then(function() {
  console.log('promise1'); 
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
}, function(err){
  console.log(err, 'errInRejectCallback'); 
}
).catch(function(err) {
  console.log('promise2');
  console.log(err, 'errInCatch');
});

如果reject,然后有第二个参数兜住,便不会被catch捕获

image.png

但catch有一个好处,就是在fulfilled callback中抛出异常也能捕获到,二reject callback捕获不到

所以我们应该用catch去捕获错误,不用reject callback捕获,也和我们平常用的try catch一致

Promise.resolve().then(function() {
  console.log('promise1');
  throw new Error('fulfilled 错了')
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
}, function(err){
  console.log(err, 'errInRejectCallback'); 
}
).catch(function(err) {
  console.log('promise2');
  console.log(err, 'errInCatch');
});

image.png

那then在没有返回值的情况下能返回一个fulfilled的promise, catch呢,我们试试吧

Promise.resolve().then(function() {
  console.log('promise1'); 
  throw new Error('fulfilled 错了')
  //这里使用了链式调用,就算不return一个promise,它也能往下跑,因为then就是一个promise
}, function(err){
  console.log(err, 'errInRejectCallback'); 
}
).catch(function(err) {
  console.log('promise2');
  console.log(err, 'errInCatch');
}).then(function(){
  console.log('catch后边链式then')
});

image.png

居然和then是一个效果,我惊了,也不是不返回任何值的情况返回的是一个fulfilled的promise

总结:使用catch不适用reject callback

catch有两个好处,就是在fulfilled callback中抛出异常也能捕获到,二reject callback捕获不到

所以我们应该用catch去捕获错误,不用reject callback捕获,也和我们平常用的try catch一致

使用reject不使用throw error,原因如下

1.  /***异步throw错误无法被捕捉***/
1.  new Promise((resolve,reject)=>{
1.      setTimeout(()=>{
1.          throw new Error('error');
1.  },0);
1.  }).then(()=>{
1.      console.log('resolve');
1.  },()=>{
1.      console.log('reject');
1.  });
1.  /***异步reject可以被捕捉***/
1.  new Promise((resolve,reject)=>{
1.      setTimeout(()=>{
1.          reject('error');
1.  },0);
1.  }).then(()=>{
1.      console.log('resolve');
1.  },()=>{
1.      console.log('reject');
1.  });

image.png

有一个很炫酷的东西,promise的值穿透

Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)

Promise.resolve(1)会返回一个promise对象并且会将1当做then的参数。而.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。所以最后会输出:1。

promise.all 和 promise.race

自己去mdn文档里跑一下

promise.race 竞速 看最快的那个,取决于进resolve还是reject promise.all 如果是全部resolve, 就进resolve callback里,然后返回一个err, 如果是有一个reject或者全部reject,就返回最慢的那个reject