【问题标题】:Dont understand javascript promise antipattern, returning promise from callback不理解 javascript 承诺反模式,从回调返回承诺
【发布时间】:2014-07-12 00:18:13
【问题描述】:

有人可以向我解释为什么在 Promise 回调中返回 Promise 被认为是反模式吗?显然它打破了异常冒泡,但显然我对承诺的理解是缺乏的,因为我无法清楚地想象它是如何工作的。我的反模式代码如下:

var a = new Promise(function (res, rej) {

    setTimeout(function () {
        res("timeout");
    }, 1000);

});

a.then(function (res) {
    console.log("a");
    console.log(res);

    return new Promise(function (res, rej) {
        console.log("b");
        setTimeout(function () {
            res("timeout2");
        }, 2000);
    }).then(function (res) {
        console.log("c");
        console.log(res);

    }).then(function (res) {
        console.log("d");
        console.log(res);

    }, function (res) {
        console.log("e");
        console.log(res);

    });

}).then(function (res) {
    console.log("l");
    console.log(res);
});

编辑:

这个问题与我的previous questions 之一有关,我在其中使用承诺做了类似的事情,其中​​一个答案说:

“您也绝不能将回调与承诺混为一谈,因为这样您就失去了异常冒泡(承诺的意义)并使您的代码超级冗长。”

所以现在我真的很困惑它是否是反模式,如果是,为什么。

【问题讨论】:

  • 这不是反模式。
  • 你说的是延迟反模式吗? github.com/petkaantonov/bluebird/wiki/…
  • @WillemD'haeseleer 我认为不是......延迟反模式是当你返回承诺或解决它时,即使你不必这样做。再说一次,我的理解可能不正确,如果是这样,请告诉我。
  • .then() 处理程序返回一个承诺是您如何使用承诺一个接一个地链接多个异步活动。这个概念没有任何反模式。您能否确定您认为您正在使用该反模式的确切位置?看来您误解了这个反模式是什么,因此清除它的唯一方法是更具体地说明您认为反模式实际上是什么。
  • @BenjaminGruenbaum:什么,使用Promise 构造函数?我认为问题是关于从 then 回调返回一个承诺。

标签: javascript promise


【解决方案1】:

“您也绝不能将回调与承诺混为一谈,因为这样您就失去了异常冒泡(承诺的意义)并使您的代码超级冗长。”

Petka 在这里的意思是,您不应在用户代码中将基于回调的方法与 Promises 一起使用,因为这会使您的代码非常冗长,如您的示例所示。

这很冗长,因为您每次调用函数时都必须根据回调手动解析或拒绝新的 Promise。

setTimeout 示例:
当超时完成时,您必须手动调用解析器。 现在 setTimeout 是一个糟糕的例子,因为它不可能拒绝它的操作。

return new Promise(function (resolve, reject) {
        console.log("b");
        setTimeout(function () {
            resolve("timeout2");
        }, 2000);
    })

更好的例子
假设你想像这样打电话给fs.readFile

return new Promise(function (resolve, reject) {
    fs.readFile('foo.txt', function (err, res) {
        if (err){
            reject(err);
            return;
        } else {
            resolve(res);
        }
    });
})

在这里你必须解决或拒绝,因为你将承诺与回调混合,这将使你的代码非常脆弱和混乱。

解决方案:

当您需要调用仅支持回调的方法时,不要到处创建新的 Promise,而是将基于回调的方法包装一次并在任何地方使用它。

var readFileAsync = new Promise(function (resolve, reject) {
    fs.readFile('foo.txt', function (err, res) {
        if (err){
            reject(err);
            return;
        } else {
            resolve(res);
        }
    });
});

奖励:

你甚至不需要做这个包裹你自己,bluebird 已经帮你搞定了。 在这里结帐承诺:

https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification

整个解释有点不合事实,即在 Promise 的 onFulfilled 方法中返回 Promise 是完全有效的。 这是 Promise/A+ 规范的一部分,请参阅 The Promise Resolution Procedure -> 2.3.2 If x is a promise, adopt its state [[3.4](#notes)]:

我认为您的困惑源于 Petka 告诉您不要在示例中创建和返回新的承诺这一事实。但这与您返回 Promise 的事实无关,而是与您不应该在那个地方创建 Promise 的事实有关,如上所述。

使用包装的版本,然后您可以将它们返回/链接到任何您想要的地方。

【讨论】:

  • 这是一个很好的答案,并且非常清楚为什么不使用带有承诺的回调,谢谢。你能解释一下为什么异常冒泡会丢失吗?
  • 实际上并没有“丢失”,只是您必须使用 Promise 自动在任何地方手动完成。
猜你喜欢
  • 2016-06-15
  • 1970-01-01
  • 2023-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-23
  • 2017-03-16
  • 2021-07-22
相关资源
最近更新 更多