javascript - 如何同时从函数返回值和 promise ?

标签 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 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 时,进程已经在路上了> 和 promiseCommand2Q.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() 适用于任意数量的调用,无需外部变量 command1command2 等。

关于javascript - 如何同时从函数返回值和 promise ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35615182/

相关文章:

php - 提交表单问题: TypeError: this.表单为空

javascript - 生成正弦波并在浏览器中播放

javascript - 如何在 AngularJS 中定义错误回调?

javascript - 从 Promise.all 解构为对象

node.js - 如何在以多部分形式处理文件流之前等待字段

javascript - 通过字符串路径访问嵌套的 JavaScript 对象和数组

javascript - window.location.href 不起作用

node.js - 如果删除 'sort',mongodb 'limit' 将不起作用

javascript - React JSX 中的动态标签名称

javascript - 组件文件夹中 index.js 的好处