Javascript 如何同时从函数返回值和承诺?
我在做这样的事情Javascript 如何同时从函数返回值和承诺?,javascript,node.js,promise,q,Javascript,Node.js,Promise,Q,我在做这样的事情 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
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()
。我曾想过将命令
传递给resolve
,但可能永远不会调用它。我还可以将命令
传递给拒绝
,这样如果出现问题,我就可以在那里调用kill
,但这感觉很奇怪
如何以惯用的方式向调用者返回命令
和承诺?在fn
中没有条件部分。有什么可能性
我还考虑了ES6的解构赋值特性,但考虑下面的
...
return [command, deferred.promise];
}
[command1, promiseCommand1] = fn('command1');
[command2, promiseCommand2] = fn('command2');
Q.all([
promise1,
promise2.then(Q.all([
promiseCommand1,
promiseCommand2
])
]);
command.promise = deferred.promise.timeout(...);
return command;
};
但这失败了(至少在我的特殊情况下,命令应该等到promise2
解决),因为当我将promisecomand1
和promisecomand2
传递到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;
})
]);
还有别的办法吗
更新
从昨天开始,我就知道如何使用解构赋值(仍然不确定语法)
这样,只有在解析了promise2
之后,才会执行命令
解决方案
根据我之前的更新,我得出了这个结论
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
,以防止我的代码因未决承诺而永久挂起。我用以下方法解决了这个问题
...
return [command, deferred.promise];
}
[command1, promiseCommand1] = fn('command1');
[command2, promiseCommand2] = fn('command2');
Q.all([
promise1,
promise2.then(Q.all([
promiseCommand1,
promiseCommand2
])
]);
command.promise = deferred.promise.timeout(...);
return command;
};
使用
timeout
将返回相同的承诺,但是如果承诺未在给定的超时值内解析,则承诺将自动被拒绝。您可以返回一个数组,然后使用promise.spread
方法
您可以返回一个数组,然后使用
promise.spread
方法
您应该通过将“passcommandtoreject”放在头上,从而得到一些有用的东西。换句话说,拒绝响应
kill()
命令
正如您所知,问题在于fn()
应该返回一个承诺,而承诺不能自然地传递相应命令的.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()
将导致“kill”在捕获处理程序中显示为error.message
这两次杀戮可以适当地调用,例如
if(...) {
promise1.kill();
}
if(...) {
promise2.kill();
}
或者,.kill()
方法也将干净地分离,而无需.bind()
,例如:
doSomethingAsync(...).then(...).catch(promise1.kill);
doSomethingElseAsync(...).then(...).catch(promise2.kill);
请注意,
fn()
将适用于任何数量的调用,而不需要外部变量command1
,command2
等。您应该通过在其头部旋转“pass command to reject”来获得有用的结果。换句话说,拒绝响应kill()
命令
正如您所知,问题在于fn()
应该返回一个承诺,而承诺不能自然地传递相应命令的.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()
将导致“kill”在捕获处理程序中显示为error.message
这两次杀戮可以适当地调用,例如
if(...) {
promise1.kill();
}
if(...) {
promise2.kill();
}
或者,.kill()
方法也将干净地分离,而无需.bind()
,例如:
doSomethingAsync(...).then(...).catch(promise1.kill);
doSomethingElseAsync(...).then(...).catch(promise2.kill);
请注意,
fn()
将适用于任何数量的调用,而不需要外部变量command1
,command2
等。promise2的问题。然后(Q.all([是的参数。然后
必须是函数)-否则,它们是有效的ignored@JaromandaX是的,我的例子是错的。但是它是有教育意义的:)promise2的问题。然后(Q.all([是的参数)。然后必须是函数-否则它们是有效的ignored@JaromandaX是的,我的例子是错的。但它是有教育意义的:)如果我从fn
返回[command,deferred.promise];
那么函数将不会返回承诺,而是返回第二个元素是承诺的数组。要使用spread
我必须解析为数组,否?deferred.resolve([…])
那么我是否可以使用spread
。无论如何,我不明白你的意思。对不起。你能详细说明一下吗?如果我返回[命令,延迟。承诺];
fromfn
则函数将不会返回承诺,而是返回第二个元素为承诺的数组。要使用spread
我必须解析为数组,否?延迟。解析([…])
那么我可以使用spread
。无论如何,我不明白你的意思。对不起。你能详细说明一下吗?很好的想法,但是我认为我做不到。我在问题中没有提到它(虽然没关系,但事实上确实如此),但我在量角器集成测试的启动前
函数中启动命令,并在启动后
中调用kill
。我从启动前
返回,并承诺延迟启动测试,直到我的进程启动