Javascript 在NodeJS中等待异步方法
我看了很多东西,只能找到如何编写异步函数,我已经理解了 我想做的是在触发事件[EventEmitter]中运行一个异步方法,但像我所发现的那样,这样简单的事情似乎根本不可能 考虑以下几点Javascript 在NodeJS中等待异步方法,javascript,node.js,asynchronous,eventemitter,Javascript,Node.js,Asynchronous,Eventemitter,我看了很多东西,只能找到如何编写异步函数,我已经理解了 我想做的是在触发事件[EventEmitter]中运行一个异步方法,但像我所发现的那样,这样简单的事情似乎根本不可能 考虑以下几点 // Your basic async method.. function doSomething(callback) { var obj = { title: 'hello' }; // Fire an event for event handlers to alter the object
// Your basic async method..
function doSomething(callback) {
var obj = { title: 'hello' };
// Fire an event for event handlers to alter the object.
// EvenEmitters are called synchronously
eventobj.emit('alter_object', obj);
callback(null, obj);
}
// when this event is fired, I want to manipulate the data
eventobj.on('alter_object', function(obj) {
obj.title += " world!";
// Calling this async function here means that our
// event handler will return before our data is retrieved.
somemodule.asyncFunction(callback(err, data) {
obj.data = data;
});
});
正如您在最后几行中所看到的,事件处理程序将在添加对象的数据属性之前完成
我需要的是,我可以将异步函数转换为同步函数,然后在那里获得结果。比如说
obj.data = somemodule.asyncFunction();
我已经研究了wait.for
模块,以及async
模块,这些模块都不能工作。我甚至研究了yield
方法,但它似乎还没有完全实现到V8引擎中
我也尝试过在循环等待数据填充时使用,但这只会带来CPU过载问题
有没有人经历过这种情况并找到了一种设计模式来解决这一问题?在node.js中不能将异步函数转换为同步函数。这是不可能做到的
如果您有一个异步结果,则无法同步返回或等待它。您必须重新设计接口以使用异步接口(这几乎总是涉及传入一个回调,当结果准备好时将调用该回调)
如果要在.emit()
事件本身将异步执行某项操作之后执行某项操作,并且要等到异步操作完成之后,则事件发射器可能不是正确的接口。您更希望有一个返回承诺或将回调作为参数的函数调用。您可以操纵eventEmitter来使用它,但是您必须在异步操作完成时回发第二个事件,并且让原始调用方在收到第二个事件之前不执行它的第二部分(这确实不是一个好方法)
一句话-您需要一种不同的设计来处理异步响应(例如回调或承诺)。看来我想做的是不可能的,而且两种模型冲突。为了最终实现我想要的,我用一些事件方法将模块封装到一个类似数组的对象中,这些事件方法将其传递给模块的对象,该对象继承了async eventemitter
类
所以,这样想吧
- 我的自定义应用程序模块可能继承async eventemitter模块,因此它们具有
.on()
和.emit()
等方法
- 我创建了一个定制的数组项,它允许我将一个事件传递给正在讨论的模块,该模块将异步工作
我创建的代码(这绝对不是完整或完美的)
然后,这允许我通过简单地调用以下内容将事件处理程序绑定到模块.on(模块名称、事件名称、回调)
然后,为了执行它,我会做一些类似(express)
同样,这只是我所做的一个例子,所以我可能在上面的副本中遗漏了一些东西,但实际上,这是我最终使用的设计,它工作得很好,我能够在推送到HTTP响应之前扩展对象上的数据,而不必替换主[expressjs]对象的标准EventEmitter模型
(例如,我为我们加载的文件添加了图像数据,我们是图像文件。如果有人想要代码,请告诉我,我非常乐意与大家分享我所做的)此外,我不能取消EventEmitter模型,因为我使用它将模块附加到crud函数中以实现模块化。在CPS中,您无法逃避嵌套回调。通过承诺,您可以将代码组织得更线性一些。使用生成器(yield),您可以编写外观同步的代码。在任何情况下,当你去异步的时候,都没有回头的路了,你基本上被困在了异步的世界里。事件监听器不是同步调用的。@elclanrs,害怕那个。。。令人困惑的是,它们呈现的事件发射器是同步的。我希望只使用回调方法,但我确实需要事件方法来实现来自其他模块的匿名连接(基本上是一个钩子系统)。关于运行回调系统的设计模式,也许我可以传递next()作为emit()中的最后一个参数,或者。此外,尽管“yield”已经完全实现,但它只是以类似同步的方式编写异步函数的解决方案的一部分。因此,EventEmitter基本上是一种设计模式,它与NodeJS的基本设计不兼容。。。。。。我正试图远离依赖性链接,因为我想根据设置的要求选择要添加到我的系统中的模块,并认为全球活动可以做到这一点。您是否有任何设计模式来替换EventEmitter对象,以方便模块的即插即用。我见过“async eventemitter”,它看起来很有前途,但很适合取代ExpressJS的事件系统。@GuyPark-不,我不会这样描述它。eventEmitter用于通知事件。它并不意味着替代函数调用,函数调用正是您试图使用它的方式。您试图emit()
一个异步引起副作用的事件,然后在发出该事件后,您试图使用该副作用。这不是事件发射器的初衷。使用带有回调的函数调用或对所做操作的承诺。这些就是为此设计的结构。异步开发需要使用适当的工具。@GuyPark-这个答案解决了您的问题吗?如果是这样,请勾选答案左侧的绿色复选标记,向社区表明您的问题已经得到了回答,然后您和提供答案的人都得到了回答
// My private indexer for accessing the modules array (below) by name.
var module_dict = {};
// An array of my modules on my (express) app object
app.modules = [];
// Here I extended the array with easier ways to add and find modules.
// Haven't removed some code to trim down this. Let me know if you want the code.
Object.defineProperty(app.modules, 'contains', { enumerable: false, ... });
Object.defineProperty(app.modules, 'find', { enumerable: false, ... });
// Allows us to add a hook/(async)event to a module, if it exists
Object.defineProperty(app.modules, 'on', { enumerable: false, configurable: false, value: function(modulename, action, func) {
if (app.modules.contains(modulename)) {
var modu = app.modules.find(modulename);
if (modu.module && modu.module['on']) {
// This will pass on the event to the module's object that
// will have the async-eventemitter inherited
modu.module.on(action, func);
}
}
} });
Object.defineProperty(app.modules, 'once', { enumerable: false, configurable: false, value: function(modulename, action, func) {
if (app.modules.contains(modulename)) {
var modu = app.modules.find(modulename);
if (modu.on) {
modu.on(action, func);
}
}
} });
app.modules.on('my_special_module_name', 'loaded', function(err, data, next) {
// ...async stuff, that then calls next to continue to the next event...
if (data.filename.endsWith('.jpg'))
data.dimensions = { width: 100, height: 100 };
next(err, data);
});
app.get('/foo', function(req, res, next) {
var data = {
filename: 'bar.jpg'
};
// Now have event handlers alter/update our data
// (eg, extend an object about a file with image data if that file is an image file).
my_special_module.emit('loaded', data, function(err, data) {
if (err) next(err);
res.send(data);
next();
});
});