Я хочу создать страницу, которая отображает некоторые данные из БД, поэтому я создал несколько функций, которые получают эти данные из моей БД. Я просто новичок в Node.js, так что, насколько я понимаю, если я захочу использовать их все на одной странице (HTTP-ответ), мне придется их всех вкладывать:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
getSomeDate(client, function(someData) {
html += "<p>"+ someData +"</p>";
getSomeOtherDate(client, function(someOtherData) {
html += "<p>"+ someOtherData +"</p>";
getMoreData(client, function(moreData) {
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
});
});
});
Если таких функций много, то вложение становится проблемой .
Есть ли способ избежать этого? Я предполагаю, что это связано с тем, как вы комбинируете несколько асинхронных функций, что кажется фундаментальным.
getSomeDate
и вgetSomeOtherDate
конечном итоге приводит к изменению отступа многих строк, что затрудняет чтение истории git (git blame
даже бесполезно после этого), и вы, вероятно, делаете ошибки при этом вручнуюОтветы:
Интересное наблюдение. Обратите внимание, что в JavaScript вы обычно можете заменить встроенные анонимные функции обратного вызова именованными переменными функций.
Последующий:
Может быть переписан, чтобы выглядеть примерно так:
Однако, если вы не планируете повторно использовать логику обратного вызова в других местах, часто намного проще читать встроенные анонимные функции, как в вашем примере. Это также избавит вас от необходимости искать имя для всех обратных вызовов.
Кроме того, обратите внимание, что, как отметил @pst в комментарии ниже, если вы обращаетесь к переменным замыкания во внутренних функциях, приведенное выше не будет простым переводом. В таких случаях использование встроенных анонимных функций еще более предпочтительно.
источник
getMoreData
потеряно.someDataParser
самом деле анализирует ВСЕ данные, так как он также вызываетgetMoreData
. В этом смысле имя функции является неправильным, и становится очевидно, что мы фактически не устранили проблему с вложенностью.Кей, просто используйте один из этих модулей.
Это превратит это:
В это:
источник
По большей части я бы согласился с Даниэлем Вассалло. Если вы можете разбить сложную и глубоко вложенную функцию на отдельные именованные функции, то обычно это хорошая идея. В тех случаях, когда имеет смысл делать это внутри одной функции, вы можете использовать одну из множества доступных асинхронных библиотек node.js. Люди придумали множество разных способов решения этой проблемы, поэтому взгляните на страницу модулей node.js и посмотрите, что вы думаете.
Я сам написал для этого модуль под названием async.js . Используя это, приведенный выше пример может быть обновлен до:
Хорошая особенность этого подхода заключается в том, что вы можете быстро изменить свой код для параллельного извлечения данных, изменив функцию 'series' на 'parallel'. Более того, async.js также будет работать в браузере, поэтому вы можете использовать те же методы, что и в node.js, если столкнетесь с каким-нибудь хитрым асинхронным кодом.
Надеюсь, это полезно!
источник
Вы можете использовать этот трюк с массивом, а не с вложенными функциями или модулем.
Гораздо проще на глазах.
Вы можете расширить идиому для параллельных процессов или даже параллельных цепочек процессов:
источник
Мне очень нравится async.js для этой цели.
Вопрос решается командой водопада:
пример
Что касается переменных req, res, они будут совместно использоваться в той же области, что и функция (req, res) {}, которая заключает в себе весь вызов async.waterfall.
Мало того, Async очень чистый. Я имею в виду, что я изменяю много таких случаев:
Для начала:
Тогда к этому:
Тогда к этому:
Это также позволяет очень быстро вызывать многие готовые функции, подготовленные для async, из util.js. Просто включите в цепочку то, что вы хотите сделать, убедитесь, что o, cb универсально обработан. Это значительно ускоряет весь процесс кодирования.
источник
Что вам нужно, это немного синтаксического сахара. Проверьте это:
Довольно аккуратно , не так ли? Вы можете заметить, что HTML стал массивом. Это отчасти потому, что строки являются неизменяемыми, поэтому лучше буферизовать вывод в массиве, чем отбрасывать все большие и большие строки. Другая причина из-за другого хорошего синтаксиса с
bind
.Queue
в примере действительно только пример и наряду сpartial
может быть реализован следующим образомисточник
last
функцией)obj.email
а ваша следующая функция использует, аobj.email
затем удаляет ее (или просто присваиваетnull
).Я влюблен в Async.js с тех пор, как нашел его. У него есть
async.series
функция, которую вы можете использовать, чтобы избежать длительного вложения.Документация:-
серия (задачи, [обратный вызов])
Запустите массив функций последовательно, каждая из которых будет запущена после завершения предыдущей функции. [...]
аргументы
tasks
- Массив функций для запуска, каждой функции передается обратный вызов, который она должна вызвать по завершении.callback(err, [results])
- Необязательный обратный вызов для запуска после завершения всех функций. Эта функция получает массив всех аргументов, переданных обратным вызовам, используемым в массиве.Вот как мы можем применить его к вашему примеру кода:
источник
Самый простой синтаксический сахар, который я видел, это обещание узла.
npm установить узел-обещание || git clone https://github.com/kriszyp/node-promise
Используя это вы можете связать асинхронные методы как:
Возвращаемое значение каждого доступно в качестве аргумента в следующем.
источник
То, что вы сделали, - это возьмите асинхронный шаблон и примените его к 3 функциям, вызываемым последовательно, каждая из которых ожидает завершения предыдущей перед запуском - т.е. вы сделали их синхронными . Суть асинхронного программирования в том, что вы можете запускать сразу несколько функций, и вам не нужно ждать завершения каждой из них.
если getSomeDate () не предоставляет ничего для getSomeOtherDate (), который ничего не предоставляет для getMoreData (), то почему бы вам не вызывать их асинхронно, как это позволяет js, или если они взаимозависимы (и не асинхронны), записать их как одна функция?
Вам не нужно использовать вложение для управления потоком - например, завершите каждую функцию, вызвав общую функцию, которая определяет, когда все 3 завершены, а затем отправляет ответ.
источник
Предположим, вы можете сделать это:
Вам нужно только реализовать chain (), чтобы она частично применяла каждую функцию к следующей и немедленно вызывала только первую функцию:
источник
ада обратного вызова можно легко избежать в чистом javascript с закрытием. Решение ниже предполагает, что все обратные вызовы следуют за сигнатурой функции (ошибка, данные).
источник
Недавно я создал более простую абстракцию под названием wait.for для вызова асинхронных функций в режиме синхронизации (на основе Fibers). Это на ранней стадии, но работает. Это в:
https://github.com/luciotato/waitfor
Используя wait.for , вы можете вызывать любую стандартную асинхронную функцию nodejs, как если бы это была функция синхронизации.
используя wait.for ваш код может быть:
... или если вы хотите быть менее многословным (а также добавить отлов ошибок)
Во всех случаях getSomeDate , getSomeOtherDate и getMoreData должны быть стандартными асинхронными функциями с последним параметром - обратным вызовом функции (ошибка, данные).
как в:
источник
Чтобы решить эту проблему, я написал nodent ( https://npmjs.org/package/nodent ), который незаметно предварительно обрабатывает ваш JS. Ваш пример кода станет (асинхронно, на самом деле - читайте документы).
Ясно, что есть много других решений, но преимущество предварительной обработки состоит в том, что она не требует больших затрат времени выполнения или вообще не требует времени выполнения, а благодаря поддержке карты исходного кода ее также легко отлаживать.
источник
У меня такая же проблема. Я видел основные библиотеки, запускающие асинхронные функции для узлов, и они представляют настолько непривычное сцепление (вам нужно использовать три или более методов и т. Д.) Для построения вашего кода.
Я потратил несколько недель на разработку простого и удобного для чтения решения. Пожалуйста, попробуйте EnqJS . Все мнения будут оценены.
Вместо того:
с EnqJS:
Обратите внимание, что код кажется больше, чем раньше. Но оно не вложено как раньше. Чтобы выглядеть более естественно, цепочки называются сразу:
И сказать, что он вернулся, внутри функции, которую мы вызываем:
источник
Я делаю это довольно примитивно, но эффективно. Например, мне нужно получить модель с ее родителями и детьми, и скажем, мне нужно сделать отдельные запросы для них:
источник
Используйте Fibers https://github.com/laverdet/node-fibers, это делает асинхронный код похожим на синхронный (без блокировки)
Лично я использую эту маленькую оболочку http://alexeypetrushin.github.com/synchronize Образец кода из моего проекта (каждый метод на самом деле асинхронный, работает с асинхронным вводом-выводом файла). Я даже боюсь представить, какой это будет беспорядок с обратным вызовом или вспомогательные библиотеки async-control-flow.
источник
Task.js предлагает вам это:
Вместо этого:
источник
После того, как другие ответили, вы заявили, что вашей проблемой являются локальные переменные. Кажется, что простой способ сделать это - написать одну внешнюю функцию, которая будет содержать эти локальные переменные, затем использовать набор именованных внутренних функций и обращаться к ним по имени. Таким образом, вы всегда будете вкладывать только две глубины, независимо от того, сколько функций вам нужно соединить вместе.
Вот попытка моего новичка использовать
mysql
модуль Node.js со вложением:Ниже приводится перезапись с использованием именованных внутренних функций. Внешняя функция также
with_connection
может использоваться в качестве держателя для локальных переменных. (Вот, у меня есть параметрыsql
,bindings
,cb
которые действуют подобным образом, но вы можете просто определить некоторые дополнительные локальные переменныеwith_connection
.)Я думал, что, возможно, можно будет создать объект с переменными экземпляра и использовать эти переменные экземпляра в качестве замены локальных переменных. Но теперь я обнаружил, что описанный выше подход с использованием вложенных функций и локальных переменных стал проще и проще для понимания. Кажется, требуется некоторое время, чтобы отучиться от ОО :-)
Итак, вот моя предыдущая версия с переменными объекта и экземпляра.
Оказывается, это
bind
может быть использовано с некоторым преимуществом. Это позволяет мне избавиться от некрасивых анонимных функций, которые я создал, которые ничего не делали, кроме как перенаправить себя на вызов метода. Я не мог передать метод напрямую, потому что он был бы связан с неправильным значениемthis
. Но с помощьюbind
я могу указать значение,this
которое я хочу.Конечно, ничего из этого не является правильным JS с кодированием Node.js - я просто потратил пару часов на это. Но, может быть, с небольшой полировкой эта техника может помочь?
источник
async.js хорошо работает для этого. Я наткнулся на эту очень полезную статью, которая объясняет необходимость и использование async.js с примерами: http://www.sebastianseilund.com/nodejs-async-in-practice
источник
Если вы не хотите использовать «step» или «seq», попробуйте «line», которая является простой функцией для уменьшения вложенного асинхронного обратного вызова.
https://github.com/kevin0571/node-line
источник
C # -подобный asyncawait это еще один способ сделать это
https://github.com/yortus/asyncawait
источник
Используя провод, ваш код будет выглядеть так:
источник
для вашего ознакомления рассмотрим Jazz.js https://github.com/Javanile/Jazz.js/wiki/Script-showcase
источник