如何包装异步函数调用到的Node.js或Javascript同步功能?
假设你保持一个公开的函数库的getData code>。您的用户调用它来获得实际的数据:结果
VAR输出=的getData();
结果
在这样你使用Node.js的内置 fs.readFileSync
实施的getData code>引擎盖数据保存在一个文件中。很明显这两个
的getData code>和
fs.readFileSync
是同步的功能。有一天,你被告知到底层数据源切换到回购,如MongoDB的只能被异步访问。您也被告知,以避免得罪了你的用户,的getData code> API不能改变仅仅返回一个承诺或要求一个回调参数。你如何满足需求?
Suppose you maintain a library that exposes a function getData
. Your users call it to get actual data:var output = getData();
Under the hood data is saved in a file so you implemented getData
using Node.js built-in fs.readFileSync
. It's obvious both getData
and fs.readFileSync
are sync functions. One day you were told to switch the underlying data source to a repo such as MongoDB which can only be accessed asynchronously. You were also told to avoid pissing off your users, getData
API cannot be changed to return merely a promise or demand a callback parameter. How do you meet both requirements?
使用回调/异步承诺的功能是JavasSript和Node.js的的DNA任何不平凡的JS应用程序可能与这种编码风格渗透。但这种做法很容易导致厄运所谓的回调金字塔。更糟的是,如果在调用链任何调用任何$ C $,c取决于异步函数的结果,那些code在回调函数被包装为好,强加给主叫方的编码风格约束。不时,我觉得需要封装一个异步函数(通常在第三方库提)进入同步功能,以避免巨大的全球性的重构。搜索关于这个问题的解决方案通常是结束了与或NPM包从它衍生出来节点纤维。但是,光纤只是解决不了,我面临的问题。即使是纤维作者提供的示例所示的不足:
Asynchronous function using callback/promise is the DNA of JavasSript and Node.js. Any non-trivial JS app is probably permeated with this coding style. But this practice can easily lead to so called callback pyramid of doom. Even worse, if any code in any caller in the call chain depends on the result of the async function, those code has to be wrapped in callback function as well, imposing a coding style constraint on caller. From time to time I find the need to encapsulate an async function (often provided in a 3rd party library) into a sync function in order to avoid massive global re-factoring. Searching for a solution on this subject usually ended up with Node Fibers or npm packages derived from it. But Fibers just cannot solve the problem I am facing. Even the example provided by Fibers' author illustrated the deficiency:
...
Fiber(function() {
console.log('wait... ' + new Date);
sleep(1000);
console.log('ok... ' + new Date);
}).run();
console.log('back in main');
实际输出:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
如果功能纤维真的出现异步功能休眠进入同步,输出应该是:
If function Fiber really turns async function sleep into sync, the output should be:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main
我在的jsfiddle 创造了另一个简单的例子,并寻找code,以产生期望的输出。我会接受的解决方案,只有这样你可以自由的进行任何NPM包,尽管没有的jsfiddle工作工作在Node.js的。
I have created another simple example in JSFiddle and looking for code to yield expected output. I'll accept a solution that only works in Node.js so you are free to require any npm package despite not working in JSFiddle.
deasync 变成异步功能分为同步,用封闭来实现通过调用Node.js的事件循环在JavaScript的层机制。其结果是,从运行而不会阻塞整个线程,也不incuring忙等待deasync仅几个街区随后code。有了这个模块,这里是答案的jsfiddle挑战:
deasync turns async function into sync, implemented with a blocking mechanism by calling Node.js event loop at JavaScript layer. As a result, deasync only blocks subsequent code from running without blocking entire thread, nor incuring busy wait. With this module, here is the answer to the jsFiddle challenge:
function AnticipatedSyncFunction(){
var ret;
setTimeout(function(){
ret = "hello";
},3000);
while(ret === undefined) {
require('deasync').runLoopOnce();
}
return ret;
}
var output = AnticipatedSyncFunction();
//expected: output=hello (after waiting for 3 sec)
console.log("output="+output);
//actual: output=hello (after waiting for 3 sec)
(声明:我是 deasync
的合着者该模块张贴了这个问题之后创建并没有发现任何可行的提案)
(disclaimer: I am the co-author of deasync
. The module was created after posting this question and found no workable proposal.)