像在 Q 中定义空的 Bluebird 承诺

Posted

技术标签:

【中文标题】像在 Q 中定义空的 Bluebird 承诺【英文标题】:Define empty Bluebird promise like in Q 【发布时间】:2014-05-06 06:01:27 【问题描述】:

使用 Q 我可以定义一个新的承诺:

var queue = q();

但如果我这样做的话,可以使用 Bluebird:

var queue = new Promise();

我明白了:

TypeError: the promise constructor requires a resolver function

我怎样才能得到与 Q 相同的结果?

这是我的代码的 sn-p:

var queue    = q()
    promises = [];
queue = queue.then(function () 
    return Main.gitControl.gitAdd(fileObj.filename, updateIndex);
);
// Here more promises are added to queue in the same way used above...
promises.push(queue);
return Promise.all(promises).then(function () 
   // ...
);

【问题讨论】:

仅供参考q 功能与Promise.cast 相同,而Promise 功能与q.promise 相同。所以q()的等价物是Promise.cast() 【参考方案1】:

Florian 提供了一个很好的答案 就您最初的问题而言,有几种方法可以使用 Bluebird 启动连锁店。

最简单的方法之一是在任何情况下都调用Promise.resolve()

var queue = Promise.resolve(); //resolve a promise with nothing or cast a value

Promise.try(function(...)
    return ...//chain here
);

所以你可以这样做:

var queue    = Promise.resolve()
    promises = [];
queue = queue.then(function () 
    return Main.gitControl.gitAdd(fileObj.filename, updateIndex);
);

// Here more promises are added to queue in the same way used above...
promises.push(queue);
return Promise.all(promises).then(function () 
   // ...
);

虽然,我个人会做这样的事情:

//arr is your array of fileObj and updateIndex

Promise.map(arr,function(f) return Main.gitControl.gitAdd(f.filename,f.updateIndex).
    then (function(result)
        //results here
    );

【讨论】:

如果你想让每个 gitAdd 等待下一个,你应该使用Promise.reduce 而不是Promise.map 为什么Promise.resolve()Promise.cast() 更好? @FlorianMargaine 好问题,Promsie.resolve 在 ES6 规范中,创建 API 时 Promise.cast 和 Promise.resolve 都在 ES6 规范和 Bluebird 中,我假设 .cast 是将在 Bluebird 2.0 中删除。 Bluebird.defer()Bluebird.cast() 在 2.x 版本中都已弃用,要启动“干净”的承诺链,最好使用 Bluebird.resolve() @pocesar 是正确的,我将删除 .cast,因为我们在 2.0(甚至 1.X iirc)中弃用了它,我在哪里错过了 .defer【参考方案2】:
var resolver = Promise.defer();
setTimeout(function() 
    resolver.resolve(something); // Resolve the value
, 5000);
return resolver.promise;

此行在documentation 中经常使用。

请注意,这通常是使用它的反模式。但如果你知道自己在做什么,Promise.defer() 是一种获取解析器的方式,类似于 Q 的方式。

但是,不鼓励使用这种方法。 Bluebird 甚至已经弃用它。

相反,您应该使用这种方式:

return new Promise(function(resolve, reject) 
    // Your code
);

请参阅相关文档位:Promise.defer() 和 new Promise()。


更新您的问题后,这是您的问题:您正在重复使用相同的承诺来解决多个值。 一个promise只能被解决一次。这意味着你必须使用Promise.defer(),就像你有promise一样多次。

也就是说,在查看了更多代码之后,您似乎真的在使用反模式。使用 Promise 的优点之一是错误处理。对于您的情况,您只需要以下代码:

var gitControl = Promise.promisifyAll(Main.gitControl);
var promises = [];
promises.push(gitControl.gitAddAsync(fileObj.filename, updateIndex));
return promises;

这应该足以处理你的用例了。它清晰了很多,而且它还具有真正正确处理错误的优点。

【讨论】:

谢谢,我会放一个“FIXME”来用推荐的方法替换当前的方法。关于Q的方式...我应该使用var resolver = Promise.defer(),queue = new Promise(resolver);吗?它会引发同样的错误。 @FezVrasta 查看progress 示例以查看Promise.defer() 的用法。 我已经更新了我的问题,添加了我的代码的 sn-p,我无法在那里实现你建议的方法,我得到同样的错误......你能帮帮我吗? @FezVrasta 在您的示例中,您只向您的 promises 数组添加了一个承诺。仅仅是为了举例吗? @FlorianMargaine +1 你能解释一下为什么new Promise(function(...Promise.defer() 更受欢迎吗?仅仅因为它“尴尬”和“容易出错”?【参考方案3】:

我遇到了这个问题,因为我有一个方法可以在 Internet 上获取资源并返回内容,但我希望它能够处理连接超时并重试多达 X 次,两者之间有延迟。

由于 Bluebird.defer 已被弃用,我使用了这个来实现这个技巧:

const Promise = require('bluebird');

var fetch = function (options, promise) 
    var resolve, reject;
    if (promise) 
        resolve = promise.resolve;
        reject = promise.reject;
        promise = promise.promise;
     else 
        promise = new Promise(function () 
            resolve = arguments[0];
            reject = arguments[1];
        );
    
    var retry = promise: promise, resolve: resolve, reject: reject;

    // Your logic here that you want to retry
    if (typeof options.x === 'undefined') 
        reject(new Error('X not defined'));
     else if (options.x < 3) 
        options.x++;
        options.retryAttempt = (options.retryAttempt || 0) + 1;
        console.log(`Retrying in 1 second attempt $options.retryAttempt...`);
        setTimeout(() => 
            fetch(options, retry)
        , 1000);
     else 
        resolve(options.x);
    

    return promise;


fetch(x:0)
    .then(res => 
        console.log(res);
    )
    .catch(err => 
        throw err;
    );

【讨论】:

【参考方案4】:

我发现这样的模式对任何类型的集成测试都很有用。

const responseResolver;

const response = new Promise(resolve => 
    responseResolver = resolve;
).then(data => 
    console.log("data: ", data);
    return data;
);

// mock some method that returns a promise (e.g. waits for a response)
service.getIceCreams = () => response;

// do some assertions while the response is pending

responseResolver("cookie dough"); // will trigger .then: "data: cookie dough"

// do some assertions now that the response is completed

【讨论】:

以上是关于像在 Q 中定义空的 Bluebird 承诺的主要内容,如果未能解决你的问题,请参考以下文章

为啥在使用promise时使用Q,bluebird框架? [复制]

如何使用 Bluebird 承诺 NodeJS Express

在Bluebird中刷新所有已解决的承诺

无法得到我在 nodejs / mongoose / bluebird 中返回的承诺

非 Promise 值的“等待”无效(Bluebird 承诺)

与 fs 和 bluebird 的承诺