我正在做这样的事情
var command1;
var command2;
var fn = function(param) {
var deferred = Q.defer();
var command = spawn(..., [
... passing different arguments based on param ...
]);
...
command.stdout.on('data', function(data) {
if (/... if process started successfully .../.test(data)) {
deferred.resolve();
}
});
...
if (param === 'command1') {
command1 = command;
} else {
command2 = command;
}
return deferred.promise;
};
Q.all([
fn('command1'),
fn('command2')
]);
稍后我将调用 command1.kill()
和 command2.kill()
。我考虑过将 command
传递给 resolve
,但它可能永远不会被调用。我也可以将 command
传递给 reject
,这样如果出现问题我就可以在那里调用 kill
,但这感觉很奇怪。
如何以惯用的方式将命令和 promise 返回给调用者?没有 fn
中的条件部分。有哪些可能性?
我也考虑过 ES6 的解构赋值功能,但请考虑以下内容
...
return [command, deferred.promise];
}
[command1, promiseCommand1] = fn('command1');
[command2, promiseCommand2] = fn('command2');
Q.all([
promise1,
promise2.then(Q.all([
promiseCommand1,
promiseCommand2
])
]);
但这失败了(至少在我的特殊情况下,命令应该等到 promise2
解决),因为当我传递 promiseCommand1
时,进程已经在路上了> 和 promiseCommand2
到 Q.all
。
不确定我是否使用了正确的解构赋值语法。
突然出现在我的脑海里
var command1;
var command2;
var fn = function(param, callback) {
var deferred = Q.defer();
var command = spawn(..., [...]);
...
callback(command);
return deferred.promise;
};
Q.all([
fn('command1', function(command) {
command1 = command;
}),
fn('command1', function(command) {
command2 = command;
})
]);
还有其他办法吗?
更新
从昨天开始,我就想出了如何使用解构赋值(仍然不确定语法)
Q.all([
promise1,
promise2.then(function() {
[command1, promiseCommand1] = fn('command1');
[command2, promiseCommand2] = fn('command2');
return Q.all([
promiseCommand1,
promiseCommand2
]);
})
]);
这样,命令只会在 promise2
解析后执行。
解决方案
基于the accepted answer和我之前的更新我想出了这个
command.promise = deferred.promise;
return command;
};
Q.all([
promise1,
promise2.then(function() {
command1 = fn('command1');
command2 = fn('command2');
return Q.all([command1.promise, command2.promise]);
})
]);
对我来说有效并且似乎是一个简洁的解决方案。我不想依赖 ES6 来完成解构作业。另外,我不认为我可以使用该功能将一个值分配给在范围之外声明的变量,并在本地范围内简洁地分配另一个值。返回
return {
command: command,
promise: deferred.promise
};
也是一个可能的解决方案,但不太简洁。
Q.all([
promise1,
promise2.then(function() {
var result1 = fn('command1');
var result2 = fn('command2');
command1 = result1.command;
command2 = result2.command;
return Q.all([result1.promise, result2.promise]);
})
]);
更正
在已接受答案的评论部分中,建议我在 fn
中调用 reject
以防止我的代码因待处理的 promise 而永远挂起。我已经用以下方法解决了这个问题
command.promise = deferred.promise.timeout(...);
return command;
};
使用timeout
将返回相同的promise,但是如果promise在给定的超时值内没有得到解决,promise将被自动拒绝。
最佳答案
通过彻底改变“通过命令拒绝”,您应该最终得到一些有用的东西。换句话说,拒绝响应 kill()
命令。
如您所知,问题在于 fn()
应该返回一个 Promise,而 Promise 并不能自然地传达相应命令的 .kill()
方法。然而,javascript 允许将属性(包括函数(作为方法))动态附加到对象。因此添加 .kill()
方法很简单。
var fn = function(param) {
var deferred = Q.defer();
var command = spawn(..., [
... passing different arguments based on param ...
]);
...
command.stdout.on('data', function(data) {
if (/... if process started successfully .../.test(data)) {
deferred.resolve();
}
});
...
var promise = deferred.promise;
// Now monkey-patch the promise with a .kill() method that fronts for command.kill() AND rejects the Deferred.
promise.kill = function() {
command.kill();
deferred.reject(new Error('killed')); // for a more specific error message, augment 'killed' with something unique derived from `param`.
}
return promise;
};
var promise1 = fn('command1');
var promise2 = fn('command2');
Q.all([promise1, promise2]).spread(...).catch(...);
promise1.kill()
或 promise2.kill()
将导致“killed”在 catch 中显示为 error.message
处理程序。
两次击杀可以酌情调用,比如……
if(...) {
promise1.kill();
}
if(...) {
promise2.kill();
}
或者,.kill()
方法也将干净地分离,而不需要 .bind()
,例如:
doSomethingAsync(...).then(...).catch(promise1.kill);
doSomethingElseAsync(...).then(...).catch(promise2.kill);
请注意,fn()
适用于任意数量的调用,无需外部变量 command1
、command2
等。
关于javascript - 如何同时从函数返回值和 promise ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35615182/