像在 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
无法得到我在 nodejs / mongoose / bluebird 中返回的承诺