Предположим, вы поддерживаете библиотеку, которая предоставляет функцию getData
. Ваши пользователи называют его , чтобы получить фактические данные:
var output = getData();
Под данные Колпак сохраняются в файле , так что вы реализованы с getData
помощью Node.js встроенной fs.readFileSync
. Очевидно, что обе функции getData
и fs.readFileSync
являются функциями синхронизации. Однажды вам сказали переключить базовый источник данных на репо, например MongoDB, к которому можно получить доступ только асинхронно. Вам также сказали, чтобы вы не злили своих пользователей, getData
API нельзя изменить так, чтобы он возвращал просто обещание или запрашивал параметр обратного вызова. Как вы соответствуете обоим требованиям?
Асинхронная функция с использованием обратного вызова / обещания - это ДНК JavasSript и Node.js. Любое нетривиальное JS-приложение, вероятно, пронизано этим стилем кодирования. Но такая практика легко может привести к так называемой пирамиде гибели обратных вызовов. Хуже того, если какой-либо код в любом вызывающем абоненте в цепочке вызовов зависит от результата асинхронной функции, этот код также должен быть заключен в функцию обратного вызова, налагая ограничение стиля кодирования на вызывающего. Время от времени я обнаруживаю необходимость инкапсулировать асинхронную функцию (часто предоставляемую в сторонней библиотеке) в функцию синхронизации, чтобы избежать массового глобального повторного факторинга. Поиск решения по этому поводу обычно заканчивался Node Fibers.или пакеты npm, производные от него. Но Fibers просто не могут решить проблему, с которой я столкнулся. Даже пример, приведенный автором Фиберса, иллюстрирует этот недостаток:
...
Fiber(function() {
console.log('wait... ' + new Date);
sleep(1000);
console.log('ok... ' + new Date);
}).run();
console.log('back in main');
Фактический выход:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Если функция Fiber действительно превращает спящий режим асинхронной функции в синхронизацию, вывод должен быть:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main
Я создал еще один простой пример в JSFiddle и ищу код для получения ожидаемого результата. Я приму решение, которое работает только в Node.js, поэтому вы можете потребовать любой пакет npm, несмотря на то, что он не работает в JSFiddle.
Ответы:
deasync превращает асинхронную функцию в синхронизацию, реализованную с помощью механизма блокировки, путем вызова цикла событий Node.js на уровне JavaScript. В результате deasync только блокирует выполнение последующего кода, не блокируя весь поток, не вызывая ожидания занятости. С помощью этого модуля вот ответ на вызов jsFiddle:
(отказ от ответственности: я являюсь соавтором
deasync
. Модуль был создан после публикации этого вопроса и не нашел работоспособного предложения.)источник
function AnticipatedSyncFunction(){ var ret; setTimeout(function(){ var startdate = new Date() //console.log(startdate) ret = "hello" + startdate; },3000); while(ret === undefined) { require('deasync').runLoopOnce(); } return ret; } var output = AnticipatedSyncFunction(); var startdate = new Date() console.log(startdate) console.log("output="+output);
и я ожидаю увидеть разницу в 3 секунды в выводе даты!Также есть модуль синхронизации npm. который используется для синхронизации процесса выполнения запроса.
Если вы хотите запускать параллельные запросы синхронным способом, тогда узел ограничивает это, потому что он никогда не ждет ответа. и модуль синхронизации идеально подходит для такого рода решений.
Образец кода
справочная ссылка: https://www.npmjs.com/package/sync
источник
Да. Внутри волокна функция ожидает перед регистрацией
ok
. Волокна не делают асинхронные функции синхронными, но позволяют писать синхронно выглядящий код, который использует асинхронные функции, а затем будет выполняться асинхронно внутриFiber
.Ты не можешь. Сделать асинхронный код синхронным невозможно. Вам нужно будет предусмотреть это в своем глобальном коде и с самого начала написать его в асинхронном стиле. Оборачиваете ли вы глобальный код в волокно, используете обещания, генераторы обещаний или простые обратные вызовы, зависит от ваших предпочтений.
И обещания, и волокна могут это сделать.
источник
fs
методы.Вы должны использовать обещания:
Мне больше нравятся определения стрелочных функций. Но любую строку вида «() => {...}» можно также записать как «function () {...}»
Таким образом, topDog не является асинхронным, несмотря на вызов асинхронной функции.
РЕДАКТИРОВАТЬ: Я понимаю, что очень часто вам нужно обернуть асинхронную функцию внутри функции синхронизации внутри контроллера. Для таких ситуаций есть трюк для вечеринки:
Используя это с обратными вызовами, вы можете сделать обертку, которая не использует обещания:
Применяя этот трюк к EventEmitter, вы можете получить те же результаты. Определите слушателя EventEmitter, в котором я определил обратный вызов, и испустите событие, в котором я вызвал обратный вызов.
источник
Я не могу найти сценарий, который нельзя решить с помощью узловых волокон. Приведенный вами пример с использованием узловых волокон ведет себя так, как ожидалось. Ключ состоит в том, чтобы запустить весь соответствующий код внутри волокна, поэтому вам не нужно начинать новое волокно в случайных местах.
Давайте посмотрим на пример: скажем, вы используете некую структуру, которая является точкой входа в ваше приложение (вы не можете изменить эту структуру). Эта структура загружает модули nodejs как плагины и вызывает некоторые методы в плагинах. Допустим, эта структура принимает только синхронные функции и не использует сами по себе волокна.
Есть библиотека, которую вы хотите использовать в одном из ваших плагинов, но эта библиотека является асинхронной, и вы также не хотите ее изменять.
Основной поток не может быть получен, если не работает волокно, но вы все равно можете создавать плагины, используя волокна! Просто создайте запись оболочки, которая запускает всю структуру внутри фибры, чтобы вы могли выполнять выполнение из плагинов.
Оборотная сторона: если фреймворк использует
setTimeout
илиPromise
внутри себя, он выйдет из контекста волокна. Это можно обойти с помощью насмешливыйsetTimeout
,Promise.then
и все обработчики событий.Вот как вы можете отдавать волокно, пока
Promise
не разрешится. Этот код принимает функцию async (возврат обещания) и возобновляет работу волокна, когда обещание разрешено:рамочные-entry.js
асинхронному lib.js
мой-plugin.js
мой-entry.js
При запуске
node framework-entry.js
он выдаст сообщение об ошибке:Error: yield() called with no fiber running
. Если запустить,node my-entry.js
все работает как положено.источник
Синхронизация кода Node.js важна в нескольких аспектах, таких как база данных. Но реальное преимущество Node.js заключается в асинхронном коде. Поскольку это однопоточный неблокирующий.
мы можем синхронизировать его, используя важную функциональность Fiber () Используйте await () и defer (), мы вызываем все методы, используя await (). затем замените функции обратного вызова на defer ().
Обычный асинхронный код, который использует функции обратного вызова.
Синхронизируйте приведенный выше код с помощью Fiber (), await () и defer ()
Я надеюсь, это поможет. Спасибо
источник
В настоящее время этот шаблон генератора может быть решением во многих ситуациях.
Вот пример последовательных подсказок консоли в nodejs с использованием функции async readline.question:
источник
Вы должны смотреть не на то, что происходит вокруг вызова, который создает волокно, а скорее на то, что происходит внутри волокна. Как только вы окажетесь внутри волокна, вы сможете программировать в стиле синхронизации. Например:
Внутри волокна, которое вы вызываете
f1
,f2
иsleep
как будто они синхронизированы.В типичном веб-приложении вы создадите Fiber в диспетчере HTTP-запросов. Как только вы это сделаете, вы можете написать всю свою логику обработки запросов в стиле синхронизации, даже если она вызывает асинхронные функции (fs, базы данных и т. Д.).
источник
while(true) handleNextRequest()
цикл. Оборачивание каждого обработчика запросов в волокно будет.Сначала я боролся с этим с помощью node.js, а async.js - лучшая библиотека, которую я нашел, чтобы помочь вам справиться с этим. Если вы хотите писать синхронный код с помощью узла, подход следующий.
эта программа ВСЕГДА будет производить следующее ...
источник
async
работает в вашем примере b / cmain
, который не заботится о вызывающем. Представьте, что весь ваш код заключен в функцию, которая должна возвращать результат одного из вызовов вашей асинхронной функции. Его можно легко проверить, добавивconsole.log('return');
в конец кода. В этом случае выводreturn
произойдет после,in main
но доstep 1
.Javascript - это однопоточный язык, вы не хотите блокировать весь свой сервер! Асинхронный код устраняет условия гонки, делая зависимости явными.
Научитесь любить асинхронный код!
Посмотрите на
promises
асинхронный код, не создавая пирамиды ада обратных вызовов. Я рекомендую библиотеку обещаний для node.jshttp://howtonode.org/promises
РЕДАКТИРОВАТЬ: это, безусловно, мой самый спорный ответ, теперь у узла есть ключевое слово yield, которое позволяет обрабатывать асинхронный код, как если бы он был синхронным. http://blog.alexmaccaw.com/how-yield-will-transform-node
источник