2011-06-22 67 views
64

我有這樣的代碼:如何防止Node.js在等待回調時退出?

var client = new mysql.Client(options); 
console.log('Icanhasclient'); 

client.connect(function (err) { 
    console.log('jannn'); 
    active_db = client; 
    console.log(err); 
    console.log('hest'); 

    if (callback) { 
    if (err) { 
     callback(err, null); 
    } 

    callback(null, active_db); 
    } 
}); 

我的問題是,節點立即終止,當我運行它。它打印'Icanhasclient',但沒有任何console.log內部的回調被調用。

(在這個例子是mysql node-mysql

有什麼可以做,使node.js的等待回調完成之前退出?

+1

你是什麼意思防止退出?在所有回調完成之前Nodejs不會退出。這是一個單線程的過程。 – neebz

+2

@nEEbz:如果是這樣,爲什麼我的腳本不執行回調而退出? – mikl

+0

這是連接到數據庫的問題;我不太確定爲什麼它不會觸發回調。它會給出任何錯誤嗎? – neebz

回答

39

回撥不排隊

節點運行,直到所有事件隊列是空的。回調被添加到事件隊列當呼叫如

emmiter1.on('this_event',callback). 

已執行。此調用是模塊開發人員編寫的代碼的一部分。

如果一個模塊是一個同步/阻塞版本快速端口,這可能不會發生直到操作的某些部分已經完成,併發生前所有隊列會清空,允許節點默默退出。

這是一個鬼鬼祟祟的錯誤,這是模塊開發人員在開發過程中可能沒有遇到的錯誤,因爲在擁有許多排隊隊列的繁忙系統中發生次數會少一些,因爲它們都是空的在關鍵時刻。

用戶A可能的修復/錯誤檢測器是可疑函數調用之前插入一個特殊的定時器事件。

+0

「這可能不會發生,直到部分操作已完成」 - 您能否澄清這一點?可能在一段代碼仍然運行之前退出,然後纔有機會向事件隊列添加回調? –

+0

我想這意味着如果庫已經將代碼轉換爲一個與新的異步版本同步的代碼,則可能庫創建者忘記排隊回調,事件隊列在執行過程中被清空,因此完成了未調用的回調。 –

0

我沒有看felixge/node-mysql庫,並沒有看到到API中的命令client.connect的參考。這是你試圖做出的實際召喚嗎?(不要試圖在這裏挑剔)?無論如何,恕我直言,你需要更多地考慮Javascript是如何設計的,因爲它使用的編程範例與大多數其他流行語言不同。

第一個問題,我在你的代碼中看到的是,你還沒有定義的回調,所以它實際上並不存在。我會假設console.log(回調)是未定義的。從你的代碼中,匿名函數是client.connect函數的'回調函數'。你必須在更高的範圍內定義你所稱的'回調'。例如,我將定義一個函數myCallback,使其存在於比client.connect的匿名函數更高的範圍內。查找Javacscript variable scope可能會很有用。

var myCallback(err, response) { 
     if (err) { 
     console.log('err:%s',err); 
     } else { 
     console.log('response:%s',response); 
     } 
    } 

    client.connect(err, function(response) { 
     // this anonymous function is the callback to client.connect, the var 
     // 'callback' would be undefined. 
     if (err) { 
     myCallback(err); 
     return; // Explicit call to return, else the lines below would run. 
     } 
     myCallback(null, response); 
    }); 

其次,如果你沒有明確地在Javascript中調用return,那麼函數將繼續處理。我被這個myself咬了。最後,Javascript運行一個event-driven循環,這意味着它永遠不會等待函數返回一個值,這就是爲什麼我們將所有這些回調放在首位。您可以強制Javascript行爲不同,例如通過使用while循環直到條件成立。有關操作事件循環的各種策略,請參閱caolan的「異步」庫。過度使用這些方法的主要缺點是您實際上可能會浪費CPU週期/阻塞,因爲您可能應該使用更多回調並重新考慮程序的工作方式。

30

你可以只發出的setTimeout或在使用setInterval重複超時。

如果你想檢查退出條件,你也可以做一個有條件的超時:

(function wait() { 
    if (!SOME_EXIT_CONDITION) setTimeout(wait, 1000); 
})(); 

在你的代碼的結尾將這個,控制檯也將只是等待...等待...直到你想關閉它。

+3

這是一個很好的解決方法,但不是一個漂亮的解決方案(什麼不是你的錯,而是節點的)。 – peterh

3

我的解決方案是實例化一個EventEmitter,並監聽我的自定義事件。

var eventEmitter = new process.EventEmitter(); 

然後我叫eventEmitter.emit從異步回調:

client.connect(function (err) { 
    eventEmitter.emit('myevent', {something: "Bla"}) 
}); 

在我的劇本的最後一件事是eventEmitter.on

eventEmitter.on('myevent', function(myResult){ 
    // I needed the result to be written to stdout so that the calling process could get it 
    process.stdout.write(JSON.stringify(myResult)); 
}); 

節點會再等到事件處理程序運行完。

+0

我正在越來越'process.EventEmitter不是一個構造函數'錯誤。你會建議什麼? –

+0

L瞭解如何創建EventEmitter。 https://coligo.io/nodejs-event-emitter/似乎是一個很好的資源。可能是不同版本的Node已經改變了如何創建一個。 – you786

+0

'EventEmitter'類由'events'模塊定義。因此,要創建一個新的發射器:'const EventEmitter = require('events'); var eventEmitter = new EventEmitter()'。 – CedX