Обсуждение модулей узлов является неполным,
не говоря о обратных вызовах и обработке ошибок.
Что такое обратные вызовы и почему они необходимы для
поддержки асинхронных вычислений, которые очень
полезны при написании приложений Node.js?
Как выполняется обработка ошибок в приложениях Node?
Давайте кратко поговорим об этом в этой лекции.
Прежде чем мы продолжим говорить о модулях Node и обратных вызовах,
нам нужно понять две характерные особенности самого языка JavaScript.
Прежде всего, JavaScript поддерживает то, что называется первоклассными функциями.
Что мы имеем в виду под первоклассными функциями?
В том, что функция может обрабатываться так же, как и любая другая переменная.
И, следовательно, функции могут передаваться как
параметры внутри вызовов функций к другим функциям.
И это по существу позволяет нам отправлять функции в качестве функций обратного вызова, которые могут быть
вызваны из другого модуля Node, чтобы получить некоторую работу.
Затем посмотрите, как это очень полезно при поддержке обратных вызовов в Node.js.
Второй аспект JavaScript - это поддержка Closers.
Что мы имеем в виду под закрытиями?
Особенно, если вы знакомы с функциональными языками программирования,
вы понимаете, как работает закрытие.
Функция, определенная внутри другой функции,
автоматически получает доступ к переменным, объявленным во внешней функции.
Поэтому, даже если внешняя функция завершается выполнение,
когда внутренняя функция выполняется позже, внутренняя функция все равно будет иметь доступ
к значениям переменных внутри этой внешней функции.
И это снова,
очень эффективно используется, когда мы используем обратные вызовы в приложениях Node.
Если вы привыкли к стандартному способу написания приложений,
то вы знакомы с синхронными вычислениями, где вы
указываете вычисление как набор шагов, которые должны выполняться один за другим.
Теперь, если вы организуете вычисления следующим образом,
как показано на левой стороне слайда здесь,
у нас есть вычисление один, а затем длительное вычисление,
затем вычисление два, и вычисление три.
Таким образом, в этой договоренности
давайте предположим, что вычисление два зависит от
длительных вычислений, завершающих свою работу,
тогда имеет смысл для вычисления два ждать, пока
длительное вычисление не будет завершено, прежде чем оно будет выполнено.
Теперь у нас может
быть еще одна часть работы, которая определяется вычислением три.
Вычисление три может быть в noway зависеть от вычисления два,
или длительное вычисление для завершения до его выполнения.
Поэтому в этом случае,
если мы сделаем синхронное выполнение этого
вычисления, то вычисление три
застрянет, хотя это никоим образом не зависит от завершения либо вычисления два,
либо длительных вычислений.
Таким образом, объем работы, которая должна быть выполнена вычислением три,
будет отложен, потому что это не собственная причина, не так ли?
Вместо этого задерживается из-за чего-то, что предшествует ему в последовательности вычислений.
Теперь, асинхронное вычисление, мы можем перестроить эту работу
таким образом, что вычисление, когда оно завершится,
может породить эти длительные вычисления, которые будут выполняться за кулисами независимо,
и поскольку вычисление два зависит от длительных вычислений для завершения,
то вычисление два может быть выполнено, когда длительное вычисление закончено.
Теперь это освобождает вычисления три для продолжения,
сразу после завершения вычисления.
Таким образом, этот способ организации
гарантирует, что вычисление три закончится намного быстрее, чем
застряло за длительным вычислением, и вычисление два.
Таким образом, этот подход к перестройке вашей работы очень полезен, особенно
когда у вас есть длительное
вычисление, связанное с вводом.
Таким образом, в этом случае вы можете создать вычисление привязки ввода-вывода,
и когда это завершится,
то все, что нужно сделать после этого,
может быть отправлено ему как обратный вызов.
Таким образом, вычисление два будет превращено в
обратный вызов, а затем отдано на длительное вычисление.
Поэтому, когда это завершит свою работу,
он вызовет функцию, которая заключена внутри обратного вызова.
Таким образом, это очень эффективно используется Node.js при
переорганизации вычислений в наших приложениях Node.
Теперь это очень,
очень полезно, когда мы смотрим на то, как работает сам Node.js.
Таким образом, как мы понимаем,
Node.js организован в один поточный цикл событий.
Этот однопоточный цикл событий в основном
собирает запросы по мере их поступления и выполняет его один за другим.
Всякий раз, когда ему нужно вызвать запрос ввода-вывода,
запрос ввода-вывода будет вызван,
и любая работа, которая должна быть выполнена после завершения запроса ввода-вывода,
будет заключена внутри обратного вызова.
Поэтому, когда запрос ввода-вывода завершается,
он поместит обратный вызов в очередь запросов,
и обратный вызов будет обрабатываться после этого,
циклом событий.
Таким образом, цикл событий - это непрерывный цикл,
который в основном забирает запросы из очереди запросов,
а затем обслуживает их по одному за раз.
Поэтому, когда вы вспоминаете об этом,
вы понимаете, что Node.js является однопоточным
, но в то же время
он способен достичь гораздо более быстрой скорости завершения работы,
просто из-за разумного использования обратных вызовов
и асинхронного выполнения запросов ввода-вывода,
например для файла доступа или базы данных,
или длительной обработки, которая может быть выполнена независимо за кулисами.
Теперь цикл событий Node.js обрабатывает все это,
заключается в том, что цикл событий расположен в последовательности фаз.
Так, как вы видите на диаграмме, показанной здесь,
фазы включают обработку таймера,
обработку обратного вызова ввода-вывода, затем у вас простоя, подготовка,
затем опрос, где обрабатываются входящие запросы на подключения или данные,
а затем этап проверки,
а затем, наконец, этап закрытия обратных вызовов.
Теперь некоторые подробности о том, что делается на каждом из этих этапов, перечислены справа.
В фазе таймера
цикл событий обрабатывает все, что запускается
функцией setTimeout () в JavaScript.
Вызовы ввода-вывода выполняются,
почти все обратные вызовы, которые возвращаются для
выполнения после запроса ввода-вывода, будут обрабатываться очередью обратных вызовов ввода-вывода.
Таким образом, каждый из этих этапов поддерживает свою собственную отдельную очередь,
и цикл событий Node.js собирает запросы из каждой из этих очередей и обрабатывает их.
, простаивает, подготовить, предназначен для внутреннего использования Node.js.
Опрос - это то, где он извлекает новые события ввода-вывода для обработки и, возможно,
запросы, поступающие извне.
Фаза закрытого обратного вызова обрабатывает любые закрытия сокета, которые должны быть обработаны, и так далее.
Теперь нам не нужно слишком беспокоиться обо
всех этих деталях, если нам нужно действительно написать приложение Node.js.
При необходимости, мы рассмотрим некоторые из этих деталей, как и когда
это важно для понимания того, как работает наше приложение Node.
Но на данный момент это дает вам представление
о том, как обрабатывается цикл событий Node.js.
Достаточно сказать, что этого достаточно информации для нас, чтобы
понять приложения Node и как они работают на данный момент.
Если вы хотите узнать более подробную информацию,
я дал вам ссылку на подробное описание в
документации Node.js, в котором более подробно описывается цикл событий.
С этим быстрым пониманием Node,
Callbacks и обработки ошибок,
мы перейдем к упражнению,
где мы рассмотрим, как приложение Node может писать с Callbacks,
и как ошибки могут быть обработаны внутри приложения Node.
Мы увидим повторное использование этого шаблона в последующих упражнениях
и последующих уроках конкретно,
когда мы посмотрим на Express,
и как мы строим серверные приложения с помощью Express
более подробно в более поздней части этого курса.