等待NodeJS中的异步方法



我已经看了高和低,只能找到如何写异步函数,我已经明白了。

我想做的是在一个触发事件[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;
    });
});

在最后几行中可以看到,事件处理程序将在添加对象的data属性之前完成。

我需要的是一些东西,我可以把异步函数变成一个同步函数,然后得到结果。例如,

obj.data = somemodule.asyncFunction();

我已经看过wait.for模块,async模块,这些都不会工作。我甚至研究了yield方法,但它似乎还没有完全实现到V8引擎。

我也尝试过使用while循环等待数据填充,但这只是带来了CPU过载问题。

有没有人经历过这种情况,并找到了一个设计模式来解决这个问题?

你不能在node.js中将异步函数转换为同步函数。这是不可能的。

如果你有一个异步的结果,你不能同步地返回它或者等待它。您将不得不重新设计接口以使用异步接口(这几乎总是涉及传递回调,当结果准备好时将调用该回调)。

如果你想在你.emit()一个事件之后做一些事情,这个事件本身就是异步的,你想等到异步的事情完成后再做,那么事件发射器可能不是正确的接口。你宁愿有一个函数调用返回一个承诺或回调作为参数。你可以操纵一个eventEmitter来使用它,但是你必须在异步操作完成时发回第二个事件,并且让原始调用者在接收到第二个事件之前不做它的第二部分(这真的不是一个好方法)。

底线-你需要一个不同的设计来处理异步响应(例如回调或承诺)

似乎我想做的是不可能的,两个模型冲突。为了最终实现我想要的,我将模块封装到一个类似数组的对象中,并使用一些事件方法将其传递给模块的对象,该对象继承了async-eventemitter类。

所以,这样想……

  • 我的自定义应用模块可以继承async-eventemitter模块,所以他们有.on().emit()等方法。
  • 我创建了一个自定义的数组项,这将允许我将一个事件传递给将异步工作的模块。
我创建的代码(这绝不是完整或完美的)…
// 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);
        }
    }
} });

然后允许我通过简单地调用下面的东西将事件处理程序绑定到模块….on(module_name, event_name, callback)

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

然后要执行它,我可以这样做(express)…

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

再一次,这只是我所做的一个例子,所以我可能在上面的复制中遗漏了一些东西,但实际上这是我最终使用的设计,它像一种享受一样工作,我能够在被推出到我的HTTP响应之前扩展对象上的数据,而不必替换主[expressjs]对象的标准EventEmitter模型。

(例如,我为我们加载的文件添加了图像数据,我们是图像文件。如果有人想要代码,让我知道,我很乐意分享我所做的)

最新更新