Javascript 在NodeJS中等待异步方法

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

我看了很多东西,只能找到如何编写异步函数,我已经理解了

我想做的是在触发事件[EventEmitter]中运行一个异步方法,但像我所发现的那样,这样简单的事情似乎根本不可能

考虑以下几点

// 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();
   });
});