2015-09-24 2 views
2

Я выглядел высоко и низко, и я могу только найти, как писать асинхронные функции, которые я уже понимаю.Ожидание асинхронного метода в NodeJS

То, что я пытаюсь сделать, это запустить метод async в запущенном событии [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; 
    }); 
}); 

Как вы можете видеть в последних строках, обработчик события завершится до того, как добавлено свойство данных объекта.

Что мне нужно - это то, где я могу превратить функцию async в функцию синхронизации и получить результаты там и тогда. так, например ...

obj.data = somemodule.asyncFunction(); 

Я смотрел на wait.for модуль, в async модуль, и ни один из них не будет работать. Я даже заглянул в метод yield, но, похоже, он еще не полностью внедрен в двигатель V8.

Я также пробовал использовать цикл while слишком долго, чтобы данные заполнили, но это просто приносит с собой проблему перегрузки процессора.

Кто-нибудь испытал это и нашел шаблон дизайна, чтобы обойти это?

+0

также , Я не могу покончить с моделью EventEmitter, так как я использую это для модулей для присоединения к crud-функциям для модульности. –

+0

В CPS вы не можете избежать вложенных обратных вызовов. С обещаниями вы можете упорядочить код немного более линейно. С генераторами (выход) вы можете написать синхронно выглядящий код. В любом случае, когда вы идете асинхронно, пути назад нет, вы в основном оказались в асинхронном мире. – 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-ответ, не заменяя стандартную модель EventEmitter основного объекта [expressjs].

(например, я добавил данные изображения для файлов, которые мы загружены, что мы файлы изображений. Если кто-то хочет код, дайте мне знать, я более чем счастлив поделиться тем, что я сделал)

1

Вы не можете превратить асинхронную функцию в синхронную в node.js. Это просто невозможно.

Если у вас асинхронный результат, вы не можете вернуть его синхронно или ждать его. Вам придется перепроектировать интерфейс для использования асинхронного интерфейса (который почти всегда включает передачу в обратном вызове, который будет вызываться, когда результат будет готов).

Если вы хотите что-то сделать после .emit() событий, которые сами будут делать что-то асинхронно, и вы хотите подождать, пока после завершения работы async, эмитент событий, вероятно, не является правильным интерфейсом. Вы предпочитаете вызов функции, который возвращает обещание или принимает обратный вызов в качестве аргумента. Вы можете манипулировать eventEmitter, чтобы использовать это, но вам нужно было бы отправить второе событие, когда операция async завершится, и чтобы исходный вызывающий не выполнял вторую часть, пока не получит второе событие (что на самом деле не является хорошим способом идти).

Нижняя линия - вам нужен другой дизайн, который работает с асинхронными ответами (например, обратными вызовами или обещаниями).

+0

, так что в основном EventEmitter - это шаблон дизайна, который просто не работает с базовым дизайном NodeJS ...... Я стараюсь держаться подальше от связи зависимости, так как я хотел бы выбрать модули для добавления в мою систему на основе требование установки и думал о глобальных событиях. У вас есть какие-либо дизайнерские шаблоны для замены объекта EventEmitter, который позволит легко подключать и воспроизводить модули. Я видел «async-eventemitter», который выглядит многообещающим, но было бы неплохо заменить систему событий ExpressJS. –

+1

@GuyPark - нет, я бы не охарактеризовал его таким образом. EventEmitter предназначен для уведомления о событии. Это не означает замену вызова функции, каким является то, как вы пытаетесь его использовать. Вы пытаетесь 'emit()' событие, которое вызывает побочный эффект асинхронно, а затем после испускания события вы пытаетесь использовать этот побочный эффект. Это не то, как когда-либо планировалось излучатель событий. Используйте вызов функции с обратным вызовом или обещание для того, что вы делаете. Это структуры, которые были разработаны для этого. Для разработки Async необходимо использовать соответствующие инструменты. – jfriend00

+0

@GuyPark - этот ответ решает вашу проблему?Если да, отметьте принятый ответ, установив зеленую галочку слева от этого ответа, чтобы сообщить сообществу, что на ваш вопрос был дан ответ, а затем и вы, и человек, предоставивший ответ, заработаете несколько точек репутации, которые могут привести к больше привилегий здесь на StackOverflow. – jfriend00

Смежные вопросы