【问题标题】:Why does the Promise chain work in this example, without throwing an error为什么 Promise 链在这个例子中工作,没有抛出错误
【发布时间】:2020-05-06 23:44:25
【问题描述】:

所以在第一个例子中,链一直执行到最后一个console.log,没有错误,但在第二个例子中,类似的,它确实出错了。为什么会发生这种情况,我能否以某种方式使第一个示例也引发错误?

我只知道它与向对象添加函数有关,因为如果 test 未定义,则链会中断,但我不明白如何访问对象中不存在的键不会导致错误。

编辑:我刚刚意识到我的脑残。自然访问test.something 会返回undefined 而不是错误。

// EXAMPLE 1: Weird

var test = {};

test.f1 = function(result) {
    return new Promise(function(resolve, reject) {
        console.log("result", result);
        resolve(1)
    });
}

test.f2 = function(result) {
    return new Promise(function(resolve, reject) {
        console.log("result", result);
        resolve(2)
    });
}

test.f3 = function(result) {
    return new Promise(function(resolve, reject) {
        console.log("result", result);
        resolve(3)
    });
}

test.f4 = function(result) {
    console.log("result", result);
}

test.f1(1)
.then(test.f2)
.then(test.f3)
.then(test.shouldCauseError)
.then(test.f4)
// EXAMPLE 2: As expected

new Promise(function(resolve, reject) {
    resolve(1);
})
.then(function(result) {
    return new Promise(function(resolve, reject) {
        resolve(2)
    });
})
.then(function(result) {
    return new Promise(function(resolve, reject) {
        resolve(3)
    });
})
.then(shouldCauseError)
.then(function(result) {
    console.log("result:", result);
});

【问题讨论】:

  • 如果您将函数以外的任何内容传递给 .then,它会被忽略 - 原因是 .then 可以期待 onResolved 和 onRejected 回调,因此,将函数以外的其他内容传递给onresolved 被忽略...这是如何指定 promise/A+ 规范的,因为(原始)规范中没有 .catch....catch(fn) 只是 .then(null, fn)

标签: javascript


【解决方案1】:

.then 最多接受两个参数。第一个参数,如果存在,如果上层 Promise 已解决,则运行。第二个参数,如果存在,如果上面的 Promise 被拒绝,则运行。

允许将undefined 作为第一个参数(或作为两个参数)传递给.then - 因为不存在任何参数,所以上面的 Promise 将通过 .then 不变地传递。

(另外,.then(undefined, fn) 等价于 .catch(fn)

所以,你的

.then(test.shouldCauseError)

undefined 传递到.then,这意味着上面的Promise 通过.then 没有修改(并且没有抛出) - 它转到下一个.then链,好像.then(test.shouldCauseError) 不存在一样。

由于将undefined 传递给.then 非常好,您需要一些其他方法来创建错误 - 或许将您传递给.thens 的所有内容包装在一个函数中,该函数检查传递的表达式是否是 一个函数,如果不是,则返回一个抛出的函数:

.then(validate(test.shouldCauseError))

// EXAMPLE 1: Weird

var test = {};

test.f1 = function(result) {
    return new Promise(function(resolve, reject) {
        console.log("result", result);
        resolve(1)
    });
}

test.f2 = function(result) {
    return new Promise(function(resolve, reject) {
        console.log("result", result);
        resolve(2)
    });
}

test.f3 = function(result) {
    return new Promise(function(resolve, reject) {
        console.log("result", result);
        resolve(3)
    });
}

test.f4 = function(result) {
    console.log("result", result);
}

const validate = arg => {
  if (typeof arg !== 'function') {
    return () => {
      throw new Error();
    }
  }
  return arg;
};

test.f1(1)
  .then(validate(test.f2))
  .then(validate(test.f3))
  .then(validate(test.shouldCauseError))
  .then(validate(test.f4))
  .catch((err) => {
    console.log('Error caught');
  });

您还可以将test 设为代理,当访问目标对象上不存在的属性时,它会返回一个抛出函数。

但这些都是奇怪的解决方案,因为正在解决的“问题”在 JS 中不被视为问题。如果您想避免此类错误,我更愿意使用 Typescript 之类的东西来确保我传递的内容是正确的类型,而不是 undefined

【讨论】:

  • 接受您的回答,因为validate(...) 方法对我来说是解决“问题”的好方法。
【解决方案2】:

.then 侦听器中,两个参数都是可选。也就是说,以下是完全有效的:

Promise.resolve().then() //Nothing passed to then

这和你写的一样:

Promise.resolve().then(undefined, undefined)

由于访问对象的不存在属性返回undefined,所以...

.then(test.shouldCauseError)

...本质上与...相同

.then(undefined)

...它不会抛出。


然而,在第二种情况下,它确实会抛出,但它与.then 无关:访问不存在的变量 会抛出ReferenceError

所以下面也会抛出:

shouldCauseError

...shouldCauseError 之前的值甚至可以传递给.then

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 2015-05-21
    • 1970-01-01
    • 2015-04-17
    • 2019-03-22
    • 2019-09-01
    • 1970-01-01
    相关资源
    最近更新 更多