如何在以下承诺代码中传递函数参数

How does the function arguments are passed in the following promise code

我有以下代码片段。这是一个承诺,在 2 秒后被拒绝。两秒后输出 Error my custom error

const promise = new Promise((resolve, reject) => {
  setTimeout(() => reject('my custom error'), 2000);
});

function onSuccess() {
  console.log('Success');
}

function onError(err) {
  console.log('Error', err);
}

promise.then(onSuccess);
promise.catch(onError);
// promise.catch((err) => onError(err));

你可以看到我添加了两个 promise.catch 语句。他们都给出相同的输出。我的问题是拒绝的错误参数 (my custom error) 如何在以下 catch 语句 promise.catch(onError).

中传递

promise.catch(onError); 将一个函数(来自 variable/constant onError)传递给 promise.catch,以便在 promise 被拒绝时调用它。

promise.catch((err) => onError(err)); 将函数 ((err) => onError(err)) 传递给 promise.catch,以便在 promise 被拒绝时调用它;该函数使用它接收的参数调用 onError

他们几乎做同样的事情。在这个 specific 案例中,它们做几乎完全相同的事情,因为拒绝回调永远不会用少于或多于一个参数来调用;它只会用 one 参数调用。所以第一个示例和第二个示例之间的唯一区别只是额外的包装函数。

无论哪种方式,传递给函数的错误对象都来自 promise 实现,当(如果)它调用拒绝处理程序时。


我应该指出,有时候,您是否有那个包装函数真的很重要,只是没有承诺回调。例如,两者之间存在很大差异:

result = someArray.map(parseInt);

result = someArray.map(val => parseInt(val));

这种情况的不同之处在于 map 使用 三个 个参数调用其回调,而不仅仅是一个。所以第一个最终用三个参数调用 parseInt,但第二个调用 parseInt 只有一个参数。这很好,因为 parseInt 会尝试使用那些后续参数(如果它们在那里),而这几乎肯定不是作者的意图。 (顺便说一句:在 parseInt 的情况下,您几乎总是希望对第二个参数进行硬编码:例如,parseInt(val, 10) 表示十进制。)

catch 方法接受一个回调函数。当 promise 被拒绝时,调用回调时出现错误。

在您的情况下,onError 函数就是回调。因此,当 promise 被拒绝时,它会接受回调并调用它。

一个典型的例子可以是

catch(callback) {
  // some logic 
  callback(new Error('error message'));
}

所以你的 onError 函数接收参数作为错误对象。

请查看 how a promise can typically be implemented

上的这篇媒体文章

它会让您对幕后发生的事情有更多了解。

另请注意

在这两种情况下

function onError(err) {
  console.log('Error', err);
}

promise.catch(onError);
promise.catch((err) => onError(err));

您正在传递一个函数以作为回调捕获。在第一种情况下,一个普通的函数将被调用,无论 catch 调用它的回调函数的参数是什么。因此,例如 catch 方法将 3 个参数传递给回调,所有三个参数都可用于 onError

在第二种情况下,您传递的是内联箭头函数。现在它作为回调函数调用所有参数 catch 块传递但是你只使用第一个参数并将它转发给 onError 函数

您的问题没有明确解决,但老实说,这比看起来要复杂。已经给出的答案足以回答你的问题,但你必须小心。

通常的做法是您可能需要在 .then().catch() 块中引用 this。尤其是当您的承诺属于某个上下文时,调用 onError 函数的两种不同方式可能会导致不同的意外结果。

所以说我们把所有的东西都放在一个模块里了。以下代码段不会 运行 并在您的控制台上抛出 js:21 Uncaught (in promise) TypeError: Cannot read property 'errMsg' of undefined at onError

class myModule{
  constructor(n){
    this.errMsg  = "my custome error";
    this.promise = new Promise((resolve, reject) => setTimeout(reject, n));
  }
  onSuccess() {
    console.log('Success');
  };
  onError() {
    console.log('Error', this.errMsg);
  };
}

var p = new myModule(2000);

p.promise.then(p.onSuccess)
         .catch(p.onError);

虽然这很好用;

class myModule{
  constructor(n){
    this.errMsg  = "my custome error";
    this.promise = new Promise((resolve, reject) => setTimeout(reject, n));
  }
  onSuccess() {
    console.log('Success');
  };
  onError() {
    console.log('Error', this.errMsg);
  };
}

var p = new myModule(2000);

p.promise.then(p.onSuccess)
         .catch(e => p.onError(e));

您可以使用箭头来保持 this 完好无损,但您仍然必须小心调用 onError 函数的位置。在第一个片段中,p.onError 函数通过引用传递以从 undefined 上下文中拥有和调用,而在第二个片段中,它仍然由 p.

拥有和调用。

为了坚持问题的上下文,我在这里使用了异常(拒绝)案例,但大多数时候这些恶作剧在 .then() 块中表现出来,您可能需要访问某些属性或属于 p 模块的方法。