2012-04-07 30 views
5

Tôi có và ứng dụng được viết bằng NodeJS với Express và đang cố gắng sử dụng EventEmitter để tạo một loại kiến ​​trúc plugin với các plugin cắm vào mã chính bằng cách nghe các sự kiện phát ra.NodeJS đợi gọi lại để kết thúc sự kiện phát ra

Sự cố của tôi xuất hiện khi chức năng plugin thực hiện yêu cầu không đồng bộ (để lấy dữ liệu từ mongo trong trường hợp này) điều này khiến mã plugin hoàn tất và trả về điều khiển trở lại trình phát ban đầu. trong mã plugin kết thúc.

Ví dụ:

Main App:

// We want to modify the request object in the plugin 
self.emit('plugin-listener', request); 

Plugin:

// Plugin function listening to 'plugin-listener', 'request' is an arg 
console.log(request); 

// Call to DB (async) 
this.getFromMongo(some_data, function(response){ 
    // this may not get called until the plugin function has finished! 
} 

Lý do của tôi để tránh một hàm callback trở lại mã chính từ chức năng 'getFromMongo' là có có thể là 0 hoặc nhiều plugin lắng nghe sự kiện. Lý tưởng nhất là tôi muốn có một số cách để chờ đợi những thứ DB để kết thúc trước khi trở về điều khiển các ứng dụng chính

Nhiều Cảm ơn

Trả lời

3

Sử dụng EventEmitter cho plugin/quản lý trung gian không phải là lý tưởng, bởi vì bạn không thể đảm bảo rằng người nghe đang được thực hiện tuần tự, nếu chúng có mã asynchroneous. Điều này đặc biệt là một vấn đề khi những người nghe này tương tác với nhau hoặc cùng một dữ liệu.

Đó là lý do tại sao tức là các chức năng kết nối/thể hiện phần mềm trung gian được lưu trữ trong một mảng và được thực thi sau khi khác, thay vì sử dụng EventEmitter; Họ cần phải gọi một() tiếp theo; khi họ hoàn thành nhiệm vụ của mình.

3

Bạn không thể kết hợp các cuộc gọi không đồng bộ với hành vi đồng bộ. Nếu bạn định gắn với trình phát sự kiện (có thể không lý tưởng cho bạn như Klovadis đã chỉ ra), bạn sẽ cần plugin của bạn phát ra một sự kiện kích hoạt một hàm trong ứng dụng chính chứa mã mà bạn muốn để 'chờ' để thực hiện. Bạn cũng sẽ phải theo dõi tất cả các cuộc gọi plugin bạn đã thực hiện mà bạn đang chờ các cuộc gọi sự kiện để mã chính của bạn không chạy cho đến khi tất cả các cuộc gọi plugin đã hoàn thành cuộc gọi lại MongoDB của họ.

var callList = ['pluginArgs1', 'pluginArgs2', 'pluginArgs3']; 
for (var i = 0; i < callList.length; i++){ 
    self.emit('plugin-listener', callList[i], i); 
} 

self.on('plugin-callback', function(i){ 
    callList.splice(i, 1); 
    if (callList.length < 1){ 
    //we're done, do something 
    } 
}); 
0

đã không thử nó bản thân mình nhưng bạn có thể sử dụng một tài sản trong đối tượng dữ liệu của sự kiện như một loạt các chức năng để thực hiện nó bằng mã mà phát ra sự kiện:

Listeners

foo.on('your-event', function(data) { 
    console.log(data); 
    // Then add the asynchronous code to a callbacks array 
    // in the event data object 
    data.callbacks.push(function(next) { 
    getFromMongo(some_data, function(err, result) { next(err) } 
    } 
}); 

Emitter

self.emit('your-event', data); 
// listeners have modified data object, 
// some might have added callback to data.callbacks 
// (suppose you use async) 
async.series(data.callbacks); 
1

Có cùng một loại quyết định về một số sự kiện Tôi đôi khi cần phải chờ đợi trước khi trả lại phản hồi cho khách hàng và đôi khi không (khi không có trong ngữ cảnh yêu cầu HTTP).

Cách dễ nhất cho tôi là thêm một cuộc gọi lại làm đối số cuối cùng của sự kiện.

Stuff.emit('do_some_stuff', data, data2, callback); 

Trong việc kiểm tra sự kiện nếu có một callback:

Stuff.on('do_some_stuff', function(data, data2, callback) { 
    // stuff to do 
    // ... 
    if (typeof callback === "function") return callback(err, result); 
}); 

Tôi biết rằng trộn sự kiện và callbacks có thể lộn xộn nhưng điều đó làm việc tốt cho những gì tôi cần. Giải pháp khác tôi thấy là giải pháp được đề xuất bởi @redben: thêm chức năng phát ra ở cuối sự kiện. Vấn đề khi trong ngữ cảnh HTTP là bạn cần các khóa duy nhất để các sự kiện của bạn không gây rối nếu chúng làm những thứ khác nhau cho mỗi người dùng.

Các vấn đề liên quan