Прочитав документы Node.JS (и красивую слайд-колоду ), я думаю, что в других ответах здесь не хватает смысла: Node.JS основан на идее, что стиль писать программы там, где мы ожидаем, что они блокируют ввод / вывод, неправильно, и вместо этого мы должны инициировать ввод / вывод (например, чтение базы данных или чтение сокета) и передать функцию для обработки результата ввода / вывода. вместе с просьбой.
Так что вместо этого:
var result = db.query("select.."); // blocking
// use result
Node.JS основан на идее сделать это:
db.query("select..", function (result) {
// use result
});
Авторы (Node.JS) отмечают, что этот способ программирования очень неудобен во многих системах, поскольку языки не имеют замыканий или анонимных функций, а библиотеки в основном блокируют ввод / вывод. Тем не менее, Javascript предоставляет первое (и программисты привыкли к нему, учитывая, как JS используется в браузере как событие, подобно событию), а Node.JS заполняет позднее: будучи полностью управляемой событиями библиотекой ввода / вывода без блокирующих вызовов на все.
Как это связано с функциональным программированием? Все функциональные языки программирования предоставляют конструкции замыкания, достаточно мощные, чтобы делать то, что Node.JS пытается сделать с Javascript. Большинство из них облегчают кодирование, поскольку передача замыканий, как правило, является фундаментальной для языка.
Что касается Haskell, то, используя монады, подобные вещи можно очень легко построить. Например:
doQuery :: DBConnection -> IO ()
doQuery db = do
rows <- query db "select..."
doSomething rows
doSomethingElse rows
Эти очень последовательные, обязательные строки кода на самом деле представляют собой последовательность замыканий, контролируемых монадой IO
. Это как если бы в JavaScript вы написали:
db.query("select...", function (rows) {
doSomething(rows, function () {
doSomethingElse(rows, function () { /* done */ })
})
})
По сути, при написании монадического кода на функциональном языке вы уже пишете его в форме, которую авторы Node.JS хотят, чтобы мы написали: где каждый шаг последовательного вычисления передается как завершение предыдущего. Однако посмотрите, насколько приятнее этот код в Haskell!
Кроме того, вы можете легко использовать параллельные функции Haskell, чтобы легко выполнить эту неблокирующую операцию:
forkQuery :: DBConnection -> IO ThreadId
forkQuery db = forkIO $ do
rows <- query db "select..."
doSomething rows
doSomethingElse rows
Не путайте это forkIO
с дорогой ветвью процесса, к которой вы привыкли, или даже с потоками процессов ОС. Это в основном та же легкая нить исполнения, которую использует Node.JS (только с несколько более богатой семантикой). Вы можете иметь их тысячи, как и на Node.JS.
Итак, вкратце - я думаю, что Node.JS основывается на объекте, который существует в JavaScript, но это гораздо более естественно в функциональных языках. Кроме того, я думаю, что все элементы, которые есть в Node.JS, уже существуют в Haskell и его пакетах, а затем и в некоторых. Для меня я бы просто использовал Haskell!