JavaScript Promises: then(f,f) vs then(f).catch(f)

在 JavaScript 中,我们有两种方式访问 promise 的成功状态值和失败结果:

A) 使用 promise.then(fn, fn) 的两个回调函数:

promise.then(success, error);

B) 或者使用 promise.then(fn).catch(fn) 链式调用:

promise.then(success).catch(error);

这两种相似的方式有什么不同吗?让我们一起寻找!

相同点

让我们考虑我们一直使用的回调函数:

function success(value) {
  console.log('Resolved: ', value);
}
function error(err) {
  console.log('Error: ', err);
}

success() 函数在成功状态时被调用,自然地 error() 在失败时调用。

在大多数的用例中这两种方式的结果是相似的:如果 promise 的状态为成功,success() 在下面代码中都会被调用:

Promise.resolve('Hi!').then(success, error);
// Logs 'Resolved: Hi!'
Promise.resolve('Hi!').then(success).catch(error);
// Logs 'Resolved: Hi!'

另外,在失败时,error() 被调用:

Promise.reject('Oops!').then(success, error);
// Logs 'Error: Oops!'
Promise.reject('Oops!').then(success).catch(error);
// Logs 'Error: Oops!'

不同点

两者的不同在于在 promise 的成功回调函数 success() 中返回一个失败状态的 promise 时。这种情况可能发生无效的成功状态。

让我们修改成功状态的回调函数使其返回一个失败状态的 promise:



 


function rejectSuccess(invalidValue) {
  console.log('Invalid success: ', invalidValue);
  return Promise.reject('Invalid!');
}

现在让我们在下面两种相似代码中使用 rejectSuccess








Promise.resolve('Zzz!').then(rejectSuccess, error);
// Logs 'Invalid success: Zzzzz!'
Promise.resolve('Zzz!').then(rejectSuccess).catch(error);
// Logs 'Invalid success: Zzzzz!'
// Logs 'Error: Invalid!'

rejectSuccess 返回一个失败状态的 promise 时,Promise.resolve('Zzz!').then(rejectSuccess, error) 仅仅调用了 rejectSuccess 函数。error() 回调函数没有被引用

Promise.resolve('Zzz!').then(rejectSuccess).catch(error) 调用了 rejectSuccess 是因为 promise 是成功状态的。但是 rejectSuccess 返回一个失败状态的 promise,这个状态被 .catch(error) 捕获导致 error() 回调函数被引用

可以换个思路考虑, then(rejectSuccess).catch(error) 类似于 then(rejectSuccess),then(null, error)

什么时候使用

then(rejectSuccess).catch(error) 是非常有用的,举例来说,当你考虑请求一个列表时,同时必须要考虑最小列表项。

于是,如果该列表是空白的,我们可以简单返回失败状态:






 
 
 






import axios from 'axios';
axios('/list.json')
  .then((response) => {
    const list = response.data;
    if (list.length === 0) {
      return Promise.reject(new Error('Empty list!'));
    }
    return list;
  })
  .catch((err) => {
    console.log(err);
  });

在上面的例子中,.catch(error) 会捕获请求错误和空白列表。

总结

promise.then(success, error)promise.then(success).catch(error) 之间的主要不同在于当 success 回调函数返回失败状态的 promise 时,第二种方式可以捕获失败状态。