【发布时间】:2014-11-09 10:19:21
【问题描述】:
我正在编写一个节点 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 循环会导致函数立即返回(带有尚未实现的承诺)。因此,我尝试将 while 循环的“等待”功能与实现的轮询频率结合起来
【问题讨论】:
-
好吧,也许是个疯狂的想法,但是使用 traceur 你可以使用 EC6 的 await 关键字。它会将你的代码重新编译成一个奇怪的状态机,但这可能是一个很容易解决你的情况的方法。
-
这在 JS 本身是不可能的。您需要一个用于在外部添加此功能的方法的插件。不知道这个模块好不好用,不建议用,你可以看看deasync
-
@t.niese 我确实简单地看过它......我的第一印象是它可能无法真正满足我的需求。我还发现了一个名为 exec-sync 的 NPM 模块,它在 OSX 上运行良好(它可以编译到每个平台上),但在 Ubuntu 上似乎失败了。 :(
-
@DavidMulder 我现在很想避免使用 EC6。它在我的清单上,要完全包裹起来,但如果可能的话,我现在想把自己限制在 Node 上(没有 Harmony)。我确实注意到 Task.js 看起来像是 ES6 对这个问题的回答。
-
因为
js本身不是多线程的。只要您在while(!shellResults) {}块中,就不会执行其他js代码。
标签: javascript node.js asynchronous synchronous rsvp-promise