我正在编写一个节点 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承诺实现——我编写了以下用于调用 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 循环的“等待”功能与实现的轮询频率结合起来