我正在编写节点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循环功能
答案 0 :(得分:0)
最简单的方法是在内部代码上使用同步API,如果您希望它同步,但是您想将异步代码包装为同步,对吗?
我认为这可以通过纤维(https://www.npmjs.org/package/fibers),或者更具体地说,期货来实现,这是一个小例子
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()();在光纤上运行它