2015-09-24 312 views
2

我看起來很高,並且只能找到如何編寫異步函數,這我已經理解了。等待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; 
    }); 
}); 

正如你可以在最後幾行看到,添加對象的數據屬性之前的事件處理程序將結束。

我需要的是可以將異步函數轉換爲同步函數並在那裏獲得結果的東西。因此,例如...

obj.data = somemodule.asyncFunction(); 

我已經看過了wait.for模塊,該模塊async,而這些都不是行不通的。我甚至研究過yield方法,但它似乎還沒有完全實現到V8引擎中。

我也試過使用while循環太等待數據填充,但這只是帶來了CPU超載的問題。

有沒有人遇到過這種情況,並找到了解決此問題的設計模式?

+0

還,我不能廢除EventEmitter模型,因爲我使用這個模塊來附加模塊化的crud函數。 –

+0

在CPS中,你不能逃避嵌套的回調。有了承諾,您可以更線性地組織代碼。使用生成器(yield),您可以編寫同步代碼。在任何情況下,當你走異步都沒有回頭路時,你基本上陷入了異步世界。 – elclanrs

+0

事件監聽器是**不**同步調用。 –

回答

0

似乎我想做的事情是不可能的,兩種模式相沖突。爲了最終達到我想要的效果,我將模塊封裝到一個類似數組的對象中,並使用一些事件方法將其傳遞給模塊的對象,該對象繼承了async-eventemitter類。

所以,認爲它是這樣的...

  • 我的自定義應用程序模塊可以繼承異步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); 
}); 

然後執行它,我會做這樣的事情(快遞)...

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模型。

(例如,我添加圖像數據,我們正在加載,我們是圖像文件的文件。如果有人想代碼,讓我知道,我很樂意分享我做了什麼)

1

您不能在node.js中將異步函數轉換爲同步函數。這是不能做到的。

如果您有異步結果,則無法同步返回或等待它。您將不得不重新設計接口以使用異步接口(幾乎總是需要傳遞一個將在結果準備就緒時調用的回調函數)。

如果你想在你之後做一些事情.emit()本身將要異步執行某些事情的事件,並且你希望等待異步事件完成之後事件發射器可能不是正確的接口。你寧願有一個函數調用返回一個承諾或將回調作爲參數。你可以操縱一個eventEmitter來使用它,但是當異步操作完成時你必須回發第二個事件,並且讓原始調用者在接收到第二個事件之前不會做第二個事件(這實際上不是一個好方法走)。底線 - 您需要與異步響應(例如回調或承諾)配合使用的不同設計。

+0

所以基本上EventEmitter是一個設計模式,只是不能與NodeJS的基本設計一起工作......我試圖遠離依賴關係鏈接,因爲我想選擇模塊添加到我的系統基於設置的要求,並認爲全球性的事件會做到這一點。您是否有任何設計模式來替換EventEmitter對象,以便輕鬆實現模塊的即插即用。我已經看到了看起來很有希望的'異步均衡器',但是取代ExpressJS的事件系統會很好。 –

+1

@GuyPark - 不,我不會這樣描述它。 eventEmitter用於通知事件。它並不意味着你正在嘗試使用它的功能調用的替代品。你試圖'發射'一個異步引發副作用的事件,然後在發射事件之後,你試圖使用副作用。這不僅僅是事件發射器的意圖。使用帶有回調或承諾的函數調用來處理您正在做的事情。那些是爲此設計的結構。異步開發需要使用適當的工具。 – jfriend00

+0

@GuyPark - 這個答案解決了你的問題嗎?如果是這樣,請通過選中該答案左側的綠色複選標記來標記已接受的答案,以向社區表明您的問題已得到解答,然後您和提供答案的人都將獲得一些可導致更多特權在這裏StackOverflow。 – jfriend00