javascript - 将 promise 包装到 Sync 函数中

标签 javascript node.js asynchronous synchronous rsvp-promise

我正在编写一个 Node CLI,其中同步行为通常比异步行为更合适,我希望能够利用以下约定:

 # Write functional code as an async function which returns a Promise
 function foobar() { ... }
 # Uses async function but blocks on promise fulfillments
 function foobarSync() { ... }

例如——使用 RSVP promise 实现——我编写了以下用于调用 shell 脚本的异步函数:

var shell = function (params,options) {
    options = extend({timeout: 4000},options);
    var commandResponse = '';
    var errorMessage ='';
    // resolve with a promise
    return new RSVP.Promise(function(resolve,reject) {
        var spawn = require('child_process').spawn;
        var timeout = setTimeout(function() {
            reject(new Error('Timed out')); // fulfil promise
        }, options.timeout);
        try {
            var shellCommand = spawn(params.shift(),params);
        } catch (err) {
            clearTimeout(timeout);
            reject(err); // fulfil promise
        }
        shellCommand.stdout.setEncoding('utf8');
        shellCommand.stderr.setEncoding('utf8');
        shellCommand.stdout.on('data', function (data) {
            commandResponse = commandResponse + data;
        });
        shellCommand.stderr.on('data', function (data) {
            errorMessage = errorMessage + data;
        });
        shellCommand.on('close', function (code) {
            if(code !== 0) {
                clearTimeout(timeout);
                reject({code:code, message:errorMessage}); // fulfil promise
            } else {
                clearTimeout(timeout);
                resolve(commandResponse); // fulfil promise
            }
        });
    }); 
};

这行得通,现在我想同步制作:

 # Works
 shell(['ls','-l']).then( function (results) {
      console.log('Result was: %s', results);
 });
 # Would like to see work
 var results = shellSync(['ls','-l']);

我认为适用于 shellSync 的是:

var shellSync = function (params,options) {
    options = extend({pollingInterval: 100},options);
    var shellResults = null;
    shell(params,options).then(
        function(results) {
            console.log('Results: %s', results);
            shellResults = results;
            // return results;
        },
        function(err) {
            console.log('Error: %s', err);
            shellResults = err;
            // return err;
        }
    );

    while(!shellResults) {
        // wait until a Promise is returned or broken (and sets the shellResults variable)
    }
    return shellResults;
};

不幸的是,它只是运行,永远不会返回。我虽然也许我会实现一个轮询间隔来执行条件语句而不是 while 循环:

    var polling = setInterval(function() {
        // return once shellResults is set; 
        // this setting takes place when either a resolve() or reject() 
        // is called in Promise
        if(shellResults) {
            console.log('results are available');
            clearInterval(polling);
            return shellResults; 
        }
    },options.pollingInterval);

    while(1) {
        // wait 
    }

当然,删除 while 循环会导致函数立即返回(带有尚未实现的 promise )。因此,我尝试将 while 循环的“等待”功能与实现的轮询频率结合起来

最佳答案

如果您希望内部代码同步,最简单的方法是在您的内部代码上使用同步 API,但您希望将异步代码包装为同步,对吧?

我认为这可以使用 fibers ( https://www.npmjs.org/package/fibers ) 来实现,或者更具体地说,futures,一个小例子

var Future = require("fibers/future");

// async API, will be wrapped by syncFoo
var asyncFoo = function(cb) {
  setTimeout(function() {
    cb("foo");
  }, 1500);
};

var syncFoo = function() {
  var future = new Future();
  console.log("asyncFoo will be called");
  asyncFoo(function(x) {
    future.return(x);
  });
  console.log("asyncFoo ended");
  return future.wait();
};

(function() {
console.log("* Syncfoo will be called");
syncFoo();
console.log("* Syncfoo ended");

console.log("* Syncfoo will be called again");
syncFoo();
console.log("* Syncfoo ended again");

}).future()();

更具体的代码:


var shellSync = function(params, options) {
    var future = new Future();

    options = extend({pollingInterval: 100},options);
    var shellResults = null;
    shell(params,options).then(
        function(results) {
            console.log('Results: %s', results);
            future.return({results: results});
        },
        function(err) {
            console.log('Error: %s', err);
            future.return({err: err});
        }
    );

    var ret = future.wait();
    if (ret.err) {
      throw ret.err;
    } else {
      return ret.results;
    }
};

编辑注意:您应该将所有内容包装在 (function() {...}).future()(); 中在光纤上运行它

关于javascript - 将 promise 包装到 Sync 函数中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25855677/

相关文章:

javascript - for 循环内的 Array.splice 导致错误

javascript - 使用新数据更新 D3 流图

javascript - 找到 ul 的第一个 li 来设置它的类

mysql - 是否可以使用:bind (oracle style) in MYSQL query with Node?

ios - 异步 API 调用(解析)是否仅使用 GCD? iOS

字符串转义后的javascript意外标识符?

jquery - 无法在expressjs中安装jQuery文件上传

node.js - 使用 Browserify 和 React 导入 Node 模块的循环依赖关系

javascript - Node.js异步编码难度

c++ - 如何在 C++ 中围绕异步回调创建同步包装器?