【问题标题】:Understanding Promises (using Bluebird and Node)理解 Promise(使用 Bluebird 和 Node)
【发布时间】:2015-10-23 19:36:44
【问题描述】:

我正在尝试以“正确的方式”使用 Promise,但我对这种情况感到困惑。以下是两段代码。第一个完美运行,第二个失败。我认为它们应该以相同的方式工作,但事实并非如此。在两者中,都创建了两条记录,但 isCrawlDue 仅在第一个中找到记录。我有 99% 的把握,错误在于我编写此承诺链的方式,而不是被调用的函数。

这是按预期工作的块。

clearStatements()
.then(dbFinancials.addStatement("XYZ", "type", moment.utc([2014, 0, 31]), 3, "none")
     .then(function (added1) {
        assert.isTrue(added1, "First record not added.");
        dbFinancials.addStatement("XYZ", "type", moment.utc(), 4, "none")
        .then(function (added2) {
            assert.isTrue(added2, "Second record not added.");
            dataCollection.isCrawlDue("XYZ")
            .then(function (isDue) {
                assert.isTrue(isDue, "No need for a crawl detected.");
                done();
            });
        });
    }));

这段代码添加了两个语句,但在isCrawlDue 中,没有找到这两个语句。我知道isCrawlDue 有效,因为它在上面的代码中有效。

clearStatements()
.then(dbFinancials.addStatement("XYZ", "type", moment.utc([2014, 0, 31]), 3, "none"))
.then(dbFinancials.addStatement("XYZ", "type", moment.utc(), 4, "none"))
.then(dataCollection.isCrawlDue("XYZ")
      .then(function (isDue) {
          assert.isTrue(isDue, "No need for a crawl detected.");
          done();
      }));

谁能看到我做错了什么?

【问题讨论】:

  • 这实际上可能是因为isCrawlDue 尚未定义,这与您的怀疑相反。在您的第一种情况下,标识符 isCrawlDue 在其包含函数运行之前不会导致引用查找(即 function (added2) 回调)。在您的第二个示例中,它会立即进行评估。
  • 当我输入一些console.log 语句时,我依次得到“add statement”、“add statement”和“isCrawlDue”,表明它们按我预期的顺序发生。也就是说,我不确定这是否与您立即“评估”的说法相矛盾,因为它绝对不像我认为的那样有效。如果我必须嵌套承诺,那不是违背了使用它们的目的吗?他们不是打算克服回调的深层嵌套吗?

标签: node.js promise


【解决方案1】:

.then(dbFinancials.addStatement("XYZ", "type", moment.utc([2014, 0, 31]), 3, "none"))

不是正确使用承诺。 .then 接受一个函数(当先前的 promise 被解析时将调用该函数),而是调用 addStatement 函数,并将结果作为参数提供给 .then
所以在第一个例子中,第一个addStatement 是在clearStatements() 之后立即调用的错误,而不是等待它解决。链条的其余部分工作正常。

在第二个示例中,正如@apsillers 所指出的那样,clearStatements 绝对正确,两个addStatementisCrawlDue 被一个接一个地调用,而无需等待解决。显然addStatement 还没有推送isCrawlDue 尚未找到的任何信息。

要以正确的方式重写它,您应该将addStatements 包装在一个函数中或使用bind(因为bind 实际上返回一个函数)。我将在下面的 sn-p 中使用这些不同的方式来演示我的意思

clearStatements()
.then(function(){
    return dbFinancials.addStatement("XYZ", "type", moment.utc([2014, 0, 31]), 3, "none")
})
.then(dbFinancials.addStatement.bind(dbFinancials, "XYZ", "type", moment.utc(), 4, "none"))
.then(function(){
    return dataCollection.isCrawlDue("XYZ");
})
.then(function (isDue) {
    assert.isTrue(isDue, "No need for a crawl detected.");
    done();
});

在这两种情况下,对addStatement 的调用将被延迟,直到前一个操作得到解决。而isCrawlDue 将在第二个addStatement 解决后执行

希望对你有帮助

【讨论】:

  • 谢谢;您的解决方案有效,并且您的叙述表明我仍然需要了解有关“最佳”或“正确”使用承诺的一些事情。谢谢你的课;语法肯定有一些细微差别。
【解决方案2】:

试试这个:

clearStatements()
.then(dbFinancials.addStatement("XYZ", "type", moment.utc([2014, 0, 31]), 3, "none"))
.then(dbFinancials.addStatement("XYZ", "type", moment.utc(), 4, "none"))
.then(dataCollection.isCrawlDue("XYZ"))
.then(function (isDue) {
    assert.isTrue(isDue, "No need for a crawl detected.");
    done();
});

我在dataCollection.isCrawlDue("XYZ") 后面添加了第二个结束括号并将其从末尾删除,因此.then 仅包装dataCollection.isCrawlDue("XYZ")

.then 返回一个值并期望另一个承诺,而不是承诺序列。

【讨论】:

    猜你喜欢
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    相关资源
    最近更新 更多