【问题标题】:How to pass promise results through intermediate stages如何通过中间阶段传递承诺结果
【发布时间】:2015-06-29 18:44:05
【问题描述】:

我试图在承诺的步骤之间传递中间值,但我找不到这样做的干净方法。作为一个用例,这似乎很常见,所以我希望我只是错过了一个模式,而不是完全偏离轨道。

我将 Bluebird 用于 Promise,并使用 Sequelize (SQL ORM)。

示例代码:

db.sync().then(function () {
    // When DB ready, insert some posts
    return [
        BlogPost.create(),
        BlogPost.create()
    ];
}).spread(function (post1, post2) {
    // Once posts inserted, add some comments
    return [
        post1.createComment({ content: 'Hi - on post 1' }),
        post2.createComment({ content: 'Hi - on post 2' })
    ];
}).spread(function (post1, post2) { // THE PROBLEM: Want posts here, not comments
    // Do more with posts after comments added, e.g. add tags to the posts

    // Can't do that in the above as something needs to wait for
    // comment creation to succeed successfully somewhere.

    // Want to wait on Comments promise, but keep using Posts promise result
});

到目前为止我最好的解决方案是:

db.sync().then(function () {
    // When DB ready, insert some posts
    return [
        BlogPost.create(),
        BlogPost.create()
    ];
}).spread(function (post1, post2) {
    // Once posts inserted, add some comments
    return Promise.all([
        post1.createComment({ content: 'Hi - on post 1' }),
        post2.createComment({ content: 'Hi - on post 2' })
    ]).then(function () {
        // Extra nested promise resolution to pull in the previous results
        return [post1, post2];
    });
}).spread(function (post1, post2) {
    // Do things with both posts
});

当然有更好的方法吗? Bluebird 有 .tap(),它非常接近,但不做 spread() 部分,我找不到一个简单的方法来组合。

【问题讨论】:

    标签: javascript promise sequelize.js bluebird


    【解决方案1】:

    我关闭了它,但后来又重新打开了,因为您的问题比一般问题更具体。 Make sure your read this question and answers 一般问题。

    对于 one-action-above 的特定上下文 - 您可以使用 .return 和 bluebird 来覆盖返回值:

    db.sync().then(function () {
        ...
    }).spread(function (post1, post2) {
        return Promise.all([
            post1.createComment({ content: 'Hi - on post 1' }),
            post2.createComment({ content: 'Hi - on post 2' })
        ]).return([post1, post2]); // use .return here
    }).spread(function (post1, post2) { comments
       // posts here
    });
    

    【讨论】:

    • 这种情况的一种变体是不传播。通过使用.then(function (posts) {...},您可以return Promise.all(...).return(posts) 而无需重新捆绑原始数据。当然,你必须这样做 posts[0].createComment(...)posts[1].createComment(...) 但也许这是一个较小的邪恶。无论哪种方式都没什么大不了的-至少在已知的少量帖子中没有。
    【解决方案2】:

    经过更多调查,我仍然找到了更好的答案(使用 0 承诺嵌套):

    db.sync().then(function () {
        // When DB ready, insert some posts
        return [
            BlogPost.create(),
            BlogPost.create()
        ];
    }).all().tap(function (posts) {
        // Once posts inserted, add some comments
        return [
            posts[0].createComment({ content: 'Hi - on post 1' }),
            posts[1].createComment({ content: 'Hi - on post 2' })
        ]
    }).spread(function (post1, post2) {
        // Do things with both posts
    });
    

    注意点击之前的 .all() :这可以确保在到达 tap() 之前正确解开第一个 then() 的结果,并允许您正常使用点击。仍然没有给你 spread() 支持,但它已经足够接近了。

    【讨论】:

      猜你喜欢
      • 2017-08-04
      • 2018-03-18
      • 2017-08-07
      • 1970-01-01
      • 2018-11-30
      • 1970-01-01
      • 2017-11-28
      • 1970-01-01
      • 2017-08-14
      相关资源
      最近更新 更多