如何同时 return 一个值和一个函数的承诺?
How to return a value and a promise from a function at the same time?
我正在做这样的事情
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
,但这感觉很奇怪。
我如何 return command
以及如何以惯用的方式向调用者承诺?没有 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
解决后执行。
解决方案
基于和我之前的更新,我想到了这个
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
以防止我的代码因未决承诺而永远挂起。我已经用以下方法解决了这个问题
command.promise = deferred.promise.timeout(...);
return command;
};
使用 timeout
将 return 相同的承诺,但是如果在给定的超时值内未解决承诺,承诺将被自动拒绝。
你可以return一个数组,然后使用promise.spread
方法。
https://github.com/kriskowal/q#combination
.then(function () {
return [command, promise];
})
.spread(function (command, promise) {
});
你应该把你的 "pass command to reject" 颠倒过来,得到一些有用的东西。换句话说,拒绝响应 kill()
命令。
如您所知,问题在于 fn()
应该 return 承诺,而承诺不会自然地传达相应命令的 .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" 在捕获处理程序中显示为 error.message
。
二杀可以酌情调用,比如...
if(...) {
promise1.kill();
}
if(...) {
promise2.kill();
}
或者,.kill()
方法也将完全分离,无需 .bind()
,例如:
doSomethingAsync(...).then(...).catch(promise1.kill);
doSomethingElseAsync(...).then(...).catch(promise2.kill);
请注意,fn()
将适用于任意数量的调用,无需外部变量 command1
、command2
等
我正在做这样的事情
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
,但这感觉很奇怪。
我如何 return command
以及如何以惯用的方式向调用者承诺?没有 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
解决后执行。
解决方案
基于
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
以防止我的代码因未决承诺而永远挂起。我已经用以下方法解决了这个问题
command.promise = deferred.promise.timeout(...);
return command;
};
使用 timeout
将 return 相同的承诺,但是如果在给定的超时值内未解决承诺,承诺将被自动拒绝。
你可以return一个数组,然后使用promise.spread
方法。
https://github.com/kriskowal/q#combination
.then(function () {
return [command, promise];
})
.spread(function (command, promise) {
});
你应该把你的 "pass command to reject" 颠倒过来,得到一些有用的东西。换句话说,拒绝响应 kill()
命令。
如您所知,问题在于 fn()
应该 return 承诺,而承诺不会自然地传达相应命令的 .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" 在捕获处理程序中显示为 error.message
。
二杀可以酌情调用,比如...
if(...) {
promise1.kill();
}
if(...) {
promise2.kill();
}
或者,.kill()
方法也将完全分离,无需 .bind()
,例如:
doSomethingAsync(...).then(...).catch(promise1.kill);
doSomethingElseAsync(...).then(...).catch(promise2.kill);
请注意,fn()
将适用于任意数量的调用,无需外部变量 command1
、command2
等