Главная страница
Навигация по странице:

  • Установка старых версий npm-пакетов

  • Обновление зависимостей проекта до их самых свежих версий

  • Локальная или глобальная деинсталляция пакетов

  • О выборе между глобальной и локальной установкой пакетов

  • О зависимостях проектов

  • Использование npx для упрощения запуска локальных команд

  • Выполнение утилит без необходимости их установки

  • Запуск JavaScript-кода с использованием различных версий Node.js

  • Часть 6: цикл событий, стек вызовов, таймеры Цикл событий

  • Блокировка цикла событий

  • Цикл событий и стек вызовов

  • Постановка функции в очередь на выполнение

  • Рекурсивная установка setTimeout()

  • Протоколы http и WebSocket Часть 9 работа с файловой системой Часть 10 стандартные модули, потоки, базы данных, node env


    Скачать 1.79 Mb.
    НазваниеПротоколы http и WebSocket Часть 9 работа с файловой системой Часть 10 стандартные модули, потоки, базы данных, node env
    Дата03.03.2019
    Размер1.79 Mb.
    Формат файлаpdf
    Имя файлаee86eb4f-db9f-48d3-8094-c76e14414678.pdf
    ТипПротокол
    #69437
    страница4 из 9
    1   2   3   4   5   6   7   8   9

    Часть 5: npm и npx
    Выяснение версий установленных npm-пакетов
    Для того чтобы узнать версии всех установленных в папке проекта npm-пакетов, включая их зависимости, выполните следующую команду: npm list
    В результате, например, может получиться следующее:
    > npm list
    /Users/flavio/dev/node/cowsay
    └─┬ cowsay@1.3.1
    ├── get-stdin@5.0.1
    ├─┬ optimist@0.6.1

    │ ├── minimist@0.0.10
    │ └── wordwrap@0.0.3
    ├─┬ string-width@2.1.1
    │ ├── is-fullwidth-code-point@2.0.0
    │ └─┬ strip-ansi@4.0.0
    │ └── ansi-regex@3.0.0
    └── strip-eof@1.0.0
    То же самое можно узнать и просмотрев файл ​package-lock.json​ проекта, но древовидную структуру, которую выводит вышеописанная команда, удобнее просматривать.
    Для того чтобы получить подобный список пакетов, установленных глобально, можно воспользоваться следующей командой: npm list -g
    Вывести только сведения о локальных пакетах верхнего уровня (то есть, тех, которые вы устанавливали самостоятельно и которые перечислены в ​package.json​) можно так: npm list --depth=0
    В результате, если, например, устанавливали вы только пакет cowsay, выведено будет следующее:
    > npm list --depth=0
    /Users/flavio/dev/node/cowsay
    └── cowsay@1.3.1
    Для того чтобы узнать версию конкретного пакета, воспользуйтесь следующей командой: npm list cowsay
    В результате её выполнения получится примерно следующее:
    > npm list cowsay
    /Users/flavio/dev/node/cowsay
    └── cowsay@1.3.1
    Эта команда подходит и для выяснения версий зависимостей установленных вами пакетов. При этом в качестве имени пакета, передаваемого ей, выступает имя пакета-зависимости, а вывод команды будет выглядеть следующим образом:
    > npm list minimist
    /Users/flavio/dev/node/cowsay
    └─┬ cowsay@1.3.1
    └─┬ optimist@0.6.1

    └── minimist@0.0.10
    Запись о пакете-зависимости в этой структуре будет выделена.
    Если вы хотите узнать о том, каков номер самой свежей версии некоего пакета, доступного в npm-репозитории, вам понадобится команда следующего вида: npm view [package_name] version
    В ответ она выдаёт номер версии пакета:
    > npm view cowsay version
    1.3.1
    Установка старых версий npm-пакетов
    Установка старой версии npm-пакета может понадобиться для решения проблем совместимости.
    Установить нужную версию пакета из npm можно, воспользовавшись следующей конструкцией: npm install
    @
    В случае с используемым нами в качестве примера пакетом cowsay, команда npm ​install cowsay установит его самую свежую версию (1.3.1 на момент написания этого материала). Если же надо установить его версию 1.2.0, воспользуемся такой командой: npm install cowsay@1.2.0
    Указывать версии можно и устанавливая глобальные пакеты: npm install -g webpack@4.16.4
    Если вам понадобится узнать о том, какие версии некоего пакета имеются в npm, сделать это можно с помощью такой конструкции: npm view versions
    Вот пример результата её работы:
    > npm view cowsay versions
    [ '1.0.0',
    '1.0.1',
    '1.0.2',
    '1.0.3',
    '1.1.0',
    '1.1.1',
    '1.1.2',
    '1.1.3',
    '1.1.4',
    '1.1.5',

    '1.1.6',
    '1.1.7',
    '1.1.8',
    '1.1.9',
    '1.2.0',
    '1.2.1',
    '1.3.0',
    '1.3.1' ]
    Обновление зависимостей проекта до их самых свежих версий
    Когда вы устанавливаете пакет командой вида ​npm install
    ​, из репозитория загружается самая свежая из доступных версий и помещается в папку ​node_modules​. При этом соответствующие записи добавляются в файлы ​package.json​ и ​package-lock.json​, находящиеся в папке проекта.
    Кроме того, устанавливая некий пакет, npm находит и устанавливает его зависимости.
    Предположим, мы устанавливаем уже знакомый вам пакет cowsay, выполняя команду ​npm install cowsay​. Пакет будет установлен в папку ​node_modules​ проекта, а в файл ​package.json​ попадёт следующая запись:
    {
    "dependencies": {
    "cowsay": "^1.3.1"
    }
    }
    В ​package-lock.json​ так же будут внесены сведения об этом пакете. Вот его фрагмент:
    {
    "requires": true,
    "lockfileVersion": 1,
    "dependencies": {
    "cowsay": {
    "version": "1.3.1",
    "resolved": "https://registry.npmjs.org/cowsay/-/cowsay-1.3.1.tgz",
    "integrity":
    "sha512-3PVFe6FePVtPj1HTeLin9v8WyLl+VmM1l1H/5P+BTTDkMAjufp+0F9eLjzRnOHzVAYeIYFF
    5po5NjRrgefnRMQ==",

    "requires": {
    "get-stdin": "^5.0.1",
    "optimist": "

    0.6.1",
    "string-width": "2.1.1",
    "strip-eof": "^1.0.0"
    }
    }
    }
    }
    Из этих двух файлов можно узнать, что мы установили cowsay версии 1.3.1, и то, что правило обновления пакета указано в виде ​^1.3.1​. В четвёртой части этой серии материалов мы уже говорили о правилах семантического версионирования. Напомним, что такая запись означает, что npm может обновлять пакет при выходе его минорных и патч-версий.
    Если, например, выходит новая минорная версия пакета и мы выполняем команду ​npm update​, то обновляется установленная версия пакета и при этом сведения об установленном пакете обновляются в файле ​package-lock.json​, а файл ​package.json​ остаётся неизменным.
    Для того чтобы узнать, вышли ли новые версии используемых в проекте пакетов, можно воспользоваться следующей командой: npm outdated
    Вот результаты выполнения этой команды для проекта, зависимости которого давно не обновлялись:

    Анализ устаревших зависимостей проекта
    Некоторые из доступных обновлений пакетов представляют собой их мажорные релизы, обновления до которых не произойдёт при выполнении команды ​npm update​. Обновление до мажорных релизов этой командой не производится, так как они (по определению) могут содержать серьёзные изменения, не отличающиеся обратной совместимостью с предыдущими мажорными релизами, а npm стремится избавить разработчика от проблем, которые может вызвать использование подобных пакетов.
    Для того чтобы обновиться до новых мажорных версий всех используемых пакетов, глобально установите пакет ​npm-check-updates​: npm install -g npm-check-updates
    Затем запустите утилиту, предоставляемую им: ncu -u
    Эта команда обновит файл ​package.json​, внеся изменения в указания о подходящих версиях пакетов в разделы ​dependencies​ и ​devDependencies​. Это позволит npm обновить пакеты, используемые в проекте, до новых мажорных версий после запуска команды ​npm update​.
    Если вы хотите установить самые свежие версии пакетов для только что только что загруженного проекта, в котором пока нет папки ​node_modules​, то, вместо ​npm update​, выполните команду ​npm install​.
    Локальная или глобальная деинсталляция пакетов
    Для того чтобы деинсталлировать пакет, ранее установленный локально (с использованием команды install
    ​), выполните команду следующего вида: npm uninstall
    Если пакет установлен глобально, то для его удаления нужно будет воспользоваться флагом​ -g
    (--global​). Например, подобная команда может выглядеть так: npm uninstall -g webpack
    При выполнении подобной команды текущая папка значения не имеет.
    О выборе между глобальной и локальной установкой пакетов
    Когда и почему пакеты лучше всего устанавливать глобально? Для того чтобы ответить на этот вопрос, вспомним о том, чем различаются локальная и глобальная установка пакетов:
    ● Локальные пакеты устанавливаются в директорию, в которой выполняют команду вида ​npm install
    ​. Такие пакеты размещаются в папке ​node_modules​, находящейся в этой директории.
    ● Глобальные пакеты устанавливаются в особую папку (в какую точно — зависит от конкретных настроек вашей системы) вне зависимости от того, где именно выполняют команду вида ​npm install -g
    ​.
    Подключение локальных и глобальных пакетов в коде осуществляется одинаково: require('package-name')
    Итак, какой же способ установки пакетов лучше всего использовать?

    В общем случае, все пакеты следует устанавливать локально. Благодаря этому, даже если у вас имеются десятки Node.js-проектов, можно обеспечить, при необходимости, использование ими различных версий одних и тех же пакетов.
    Обновление глобального пакета приводит к тому, что все проекты, в которых он применяется, будут использовать его новый релиз. Несложно понять, что это, в плане поддержки проектов, может привести к настоящему кошмару, так как новые релизы некоторых пакетов могут оказаться несовместимыми с их старыми версиями.
    Если у каждого проекта имеется собственная локальная версия некоего пакета, даже при том, что подобное может показаться пустой тратой ресурсов, это — очень небольшая плата за возможность избежать негативных последствий, которые могут быть вызваны несовместимостью новых версий пакетов, обновляемых централизованно, с кодом проектов.
    Пакеты следует устанавливать глобально в том случае, когда они представляют собой некие утилиты, вызываемые из командной строки, которые используются во множестве проектов.
    Подобные пакеты можно устанавливать и локально, запуская предоставляемые ими утилиты командной строки с использованием npx, но некоторые пакеты, всё же, лучше устанавливать глобально. К таким пакетам, которые вам, вполне возможно, знакомы, можно отнести, например, следующие:
    ● npm
    ● create-react-app
    ● vue-cli
    ● grunt-cli
    ● mocha
    ● react-native-cli
    ● gatsby-cli
    ● forever
    ● nodemon
    Не исключено, что в вашей системе уже имеются пакеты, установленные глобально. Для того чтобы об этом узнать, воспользуйтесь следующей командой: npm list -g --depth 0
    О зависимостях проектов
    Когда пакет следует рассматривать как обычную зависимость проекта, необходимую для обеспечения его функционирования, а когда — как зависимость разработки?
    При установке пакета с помощью команды вида ​npm install
    ​ он устанавливается как обычная зависимость. Запись о таком пакете делается в разделе ​dependencies​ файла package.json​ (до выхода npm 5 такая запись делалась только при использовании флага ​--save​, теперь использовать его для этого необязательно).
    Использование флага ​--save-dev​ позволяет установить пакет как зависимость разработки. Запись о нём при этом делается в разделе ​devDependencies​ файла ​package.json​.
    Зависимости разработки — это пакеты, которые нужны в процессе разработки проекта, в ходе его обычного функционирования они не требуются. К таким пакетам относятся, например инструменты тестирования, Webpack, Babel.

    Когда проект разворачивают, используя команду ​npm install​ в его папке, в которой имеется папка, содержащая файл ​package.json​, это приведёт к установке всех зависимостей, так как npm предполагает, что подобная установка выполняется для целей работы над проектом.
    Поэтому, если пакет требуется развернуть в продакшне, то, при его развёртывании, нужно использовать команду npm ​install --production​. Благодаря флагу ​--production​ зависимости разработки устанавливаться не будут.
    Утилита npx
    Сейчас мы поговорим об одной весьма мощной команде, ​
    npx​
    , которая появилась в npm 5.2. Одной из её возможностей является запуск исполняемых файлов, входящих в состав npm-пакетов. Мы уже рассматривали использование npx для запуска подобного файла из пакета cowsay. Теперь поговорим об этом подробнее.
    Использование npx для упрощения запуска локальных команд
    Node.js-разработчики опубликовали множество исполняемых файлов (утилит) в виде пакетов, которые предполагалось устанавливать глобально, что обеспечивало удобный доступ к их возможностям, так как запускать их из командной строки можно было, просто введя имя соответствующей команды.
    Однако работать в такой среде было весьма некомфортно в том случае, если требовалось устанавливать разные версии одних и тех же пакетов.
    Применение команды вида ​npx commandname​ приводит к автоматическому поиску нужного файла в папке проекта ​node_modules​. Это избавляет от необходимости знания точного пути к подобному файлу. Так же это делает ненужной глобальную установку пакета с обеспечением доступа к нему из любого места файловой системы благодаря использованию системной переменной ​PATH​.
    Выполнение утилит без необходимости их установки
    В npx имеется ещё одна интереснейшая возможность, благодаря которой утилиты можно запускать без их предварительной установки. Полезно это, в основном, по следующим причинам:
    ● Не требуется установка утилит.
    ● Можно запускать разные версии одних и тех же утилит, указывая нужную версию с помощью конструкции ​@version​.
    Посмотрим на то, как пользоваться этим механизмом, на примере уже известной вам утилиты ​cowsay​.
    Так, если пакет cowsay установлен глобально, выполнение в командной строке команды ​cowsay
    "Hello"​ приведёт к выводу в консоль «говорящей» коровы:
    _______
    < Hello >
    -------
    \ ^__^
    \ (oo)\_______
    (__)\ )\/\
    ||----w |
    || ||
    Если же пакет cowsay не будет установлен глобально, подобная команда выдаст ошибку.

    Утилита npx позволяет выполнять подобные команды без их установки. Выглядит это, в рамках нашего примера, так: npx cowsay "Hello"
    Такая команда сработает, но, хотя «говорящая» корова, по большому счёту, особой пользы не приносит, тот же самый подход можно использовать и для выполнения куда более полезных команд.
    Вот несколько примеров:
    ● Существует инструмент командной строки, предназначенный для создания и запуска
    Vue-приложений. С использованием npx его можно вызвать так: ​npx vue create my-vue-app​.
    ● Для создания React-приложений можно пользоваться утилитой ​create-react-app​. Её вызов через npx выглядит так: ​npx create-react-app my-react-app​.
    После загрузки и использования соответствующего кода npx его удалит.
    Запуск JavaScript-кода с использованием различных версий Node.js
    Для того чтобы запускать некий код с использованием разных версий Node.js, можно, с использованием npx, обращаться к npm-пакету ​node​, указывая его версию. Выглядит это так: npx node@6 -v #v6.14.3 npx node@8 -v #v8.11.3
    Это позволяет отказаться от использования инструментов наподобие nvm или других менеджеров версий Node.js.
    Запуск произвольных фрагментов кода, доступных по некоему адресу
    Npx позволяет запускать не только код, опубликованный в npm. В частности, если у вас есть ссылка на некий фрагмент кода (скажем, опубликованного на ​
    GitHub​
    gist), запустить его можно так: npx https://gist.github.com/zkat/4bc19503fe9e9309e2bfaa2c58074d32
    Конечно, при выполнении подобного кода нельзя забывать о безопасности. Npx даёт в руки разработчика большие возможности, но они означают и большую ответственность.
    Часть 6: цикл событий, стек вызовов, таймеры
    Цикл событий
    Если вы хотите разобраться с тем, как выполняется JavaScript-код, то цикл событий (Event Loop) — это одна из важнейших концепций, которую необходимо понять. Здесь мы поговорим о том, как JavaScript работает в однопоточном режиме, и о том, как осуществляется обработка асинхронных функций.
    Я многие годы занимался разработкой на JavaScript, но не могу сказать, что полностью понимал то, как всё функционирует, так сказать, «под капотом». Программист вполне может не знать о тонкостях устройства внутренних подсистем среды, в которой он работает. Но обычно полезно иметь хотя бы общее представление о подобных вещах.
    JavaScript-код, который вы пишете, выполняется в однопоточном режиме. В некий момент времени выполняется лишь одно действие. Это ограничение, на самом деле, является весьма полезным. Это значительно упрощает то, как работают программы, избавляя программистов от необходимости решать проблемы, характерные для многопоточных сред.

    Фактически, JS-программисту нужно обращать внимание только на то, какие именно действия выполняет его код, и стараться при этом избежать ситуаций, вызывающих блокировку главного потока.
    Например — выполнения сетевых вызовов в синхронном режиме и бесконечных ​
    цикл​ов​
    Обычно в браузерах, в каждой открытой вкладке, имеется собственный цикл событий. Это позволяет выполнять код каждой страницы в изолированной среде и избегать ситуаций, когда некая страница, в коде которой имеется бесконечный цикл или выполняются тяжёлые вычисления, способна «подвесить» весь браузер. Браузер поддерживает работу множества одновременно существующих циклов событий, используемых, например, для обработки вызовов к различным API. Кроме того, собственный цикл событий используется для обеспечения работы ​
    веб-воркеров​
    Самое важное, что надо постоянно помнить JavaScript-программисту, заключается в том, что его код использует собственный цикл событий, поэтому код надо писать с учётом того, чтобы этот цикл событий не заблокировать.
    Блокировка цикла событий
    Любой JavaScript-код, на выполнение которого нужно слишком много времени, то есть такой код, который слишком долго не возвращает управление циклу событий, блокирует выполнение любого другого кода страницы. Подобное приводит даже к блокировке обработки событий пользовательского интерфейса, что выражается в том, что пользователь не может взаимодействовать с элементами страницы и нормально с ней работать, например — прокручивать.
    Практически все базовые механизмы обеспечения ввода-вывода в JavaScript являются неблокирующими. Это относится и к браузеру и к Node.js. Среди таких механизмов, например, можно отметить средства для выполнения сетевых запросов, используемые и в клиентской и в серверной средах, и средства для работы с файлами Node.js. Существуют и синхронные способы выполнения подобных операций, но их применяют лишь в особых случаях. Именно поэтому в JavaScript огромное значение имеют традиционные коллбэки и более новые механизмы — промисы и конструкция async/await.
    Стек вызовов
    Стек вызовов (Call Stack) в JavaScript устроен по принципу LIFO (Last In, First Out — последним вошёл, первым вышел). Цикл событий постоянно проверяет стек вызовов на предмет того, имеется ли в нём функция, которую нужно выполнить. Если при выполнении кода в нём встречается вызов некоей функции, сведения о ней добавляются в стек вызовов и производится выполнение этой функции.
    Если даже раньше вы не интересовались понятием «стек вызовов», то вы, если встречались с сообщениями об ошибках, включающими в себя трассировку стека, уже представляете себе, как он выглядит. Вот, например, как подобное выглядит в браузере.

    Сообщение об ошибке в
    браузере
    Браузер, при возникновении ошибки, сообщает о последовательности вызовов функций, сведения о которых хранятся в стеке вызовов, что позволяет обнаружить источник ошибки и понять, вызовы каких функций привели к сложившейся ситуации.
    Теперь, когда мы в общих чертах поговорили о цикле событий и о стеке вызовов, рассмотрим пример, иллюстрирующий выполнение фрагмента кода, и то, как этот процесс выглядит с точки зрения цикла событий и стека вызовов.
    Цикл событий и стек вызовов
    Вот код, с которым мы будем экспериментировать: const bar = () => console.log('bar') const baz = () => console.log('baz') const foo = () => { console.log('foo') bar()
    baz()
    } foo()
    Если этот код выполнить, в консоль попадёт следующее: foo bar baz
    Такой результат вполне ожидаем. А именно, когда этот код запускают, сначала вызывается функция foo()​. Внутри этой функции мы сначала вызываем функцию ​bar()​, а потом — ​baz()​. При этом стек вызовов в ходе выполнения этого кода претерпевает изменения, показанные на следующем рисунке.
    Изменение состояния стека вызовов при выполнении исследуемого кода

    Цикл событий, на каждой итерации, проверяет, есть ли что-нибудь в стеке вызовов, и если это так — выполняет это до тех пор, пока стек вызовов не опустеет.
    Итерации цикла событий
    Постановка функции в очередь на выполнение
    Вышеприведённый пример выглядит вполне обычным, в нём нет ничего особенного: JavaScript находит код, который надо выполнить, и выполняет его по порядку. Поговорим о том, как отложить выполнение функции до момента очистки стека вызовов. Для того чтобы это сделать, используется такая конструкция: setTimeout(() => {}), 0)

    Она позволяет выполнить функцию, переданную функции ​setTimeout()​, после того, как будут выполнены все остальные функции, вызванные в коде программы.
    Рассмотрим пример: const bar = () => console.log('bar') const baz = () => console.log('baz') const foo = () => { console.log('foo') setTimeout(bar, 0) baz()
    } foo()
    То, что выведет этот код, возможно, покажется неожиданным: foo baz bar
    Когда мы запускаем этот пример, сначала вызывается функция ​foo()​. В ней мы вызываем setTimeout()​, передавая этой функции, в качестве первого аргумента, ​bar​. Передав ей в качестве второго аргумента ​0​, мы сообщаем системе о том, что эту функцию следует выполнить как можно скорее. Затем мы вызываем функцию ​baz()​.
    Вот как теперь будет выглядеть стек вызовов.

    Изменение состояния стека вызовов при выполнении исследуемого кода
    Вот в каком порядке теперь будут выполняться функции в нашей программе.

    Итерации цикла событий
    Почему всё происходит именно так?
    Очередь событий
    Когда вызывается функция ​setTimeout()​, браузер или платформа Node.js запускает таймер. После того, как таймер сработает (в нашем случае это происходит немедленно, так как мы установили его на
    0), функция обратного вызова, переданная ​setTimeout()​, попадает в очередь событий (Event Queue).
    В очередь событий, если речь идёт о браузере, попадают и события, инициированные пользователем
    — события, вызванные щелчками мышью по элементам страницы, события, вызываемые при вводе данных с клавиатуры. Тут же оказываются обработчики событий DOM вроде ​onload​, функции,
    вызываемые при получении ответов на асинхронные запросы по загрузке данных. Здесь они ждут своей очереди на обработку.
    Цикл событий отдаёт приоритет тому, что находится в стеке вызовов. Сначала он выполняет всё, что ему удаётся найти в стеке, а после того, как стек оказывается пустым, переходит к обработке того, что находится в очереди событий.
    Нам не нужно ждать, пока функция, наподобие ​setTimeout()​, завершит работу, так как подобные функции предоставляются браузером и они используют собственные потоки. Так, например, установив с помощью функции ​setTimeout()​ таймер на 2 секунды, вы не должны, остановив выполнение другого кода, ждать эти 2 секунды, так как таймер работает за пределами вашего кода.
    Очередь заданий ES6
    В ECMAScript 2015 (ES6) была введена концепция очереди заданий (Job Queue), которой пользуются промисы (они тоже появились в ES6). Благодаря очереди заданий результатом выполнения асинхронной функции можно воспользоваться настолько быстро, насколько это возможно, без необходимости ожидания очищения стека вызовов.
    Если промис разрешается до окончания выполнения текущей функции, соответствующий код будет выполнен сразу после того, как текущая функция завершит работу.
    Я обнаружил интересную аналогию для того, о чём мы сейчас говорим. Это можно сравнить с американскими горками в парке развлечений. После того, как вы прокатились на горке и хотите сделать это ещё раз, вы берёте билет и становитесь в хвост очереди. Так работает очередь событий. А вот очередь заданий выглядит иначе. Эта концепция похожа на льготный билет, который даёт вам право совершить следующую поездку сразу после того, как вы закончили предыдущую.
    Рассмотрим следующий пример: const bar = () => console.log('bar') const baz = () => console.log('baz') const foo = () => { console.log('foo') setTimeout(bar, 0) new Promise((resolve, reject) => resolve('should be right after baz, before bar')
    ).then(resolve => console.log(resolve)) baz()
    } foo()
    Вот что будет выведено после его выполнения: foo baz
    should be right after foo, before bar bar
    То, что тут можно видеть, демонстрирует серьёзное различие промисов (и конструкции async/await, которая на них основана) и традиционных асинхронных функций, выполнение которых организуется посредством ​setTimeout()​ или других API используемой платформы.
    process.nextTick()
    Метод ​process.nextTick()​ по-особому взаимодействует с циклом событий. Тиком (tick) называют один полный проход цикла событий. Передавая функцию методу ​process.nextTick()​, мы сообщаем системе о том, что эту функцию нужно вызвать после завершения текущей итерации цикла событий, до начала следующей. Использование данного метода выглядит так: process.nextTick(() => {
    //выполнить какие-то действия
    })
    Предположим, цикл событий занят выполнением кода текущей функции. Когда эта операция завершается, JavaScript-движок выполнит все функции, переданные ​process.nextTick()​ в ходе выполнения предыдущей операции. Используя этот механизм, мы стремимся к тому, чтобы некая функция была бы выполнена асинхронно (после текущей функции), но как можно скорее, без постановки её в очередь.
    Например, если воспользоваться конструкцией ​setTimeout(() => {}, 0)​ функция будет выполнена на следующей итерации цикла событий, то есть — гораздо позже, чем при использовании в такой же ситуации ​process.nextTick()​. Этот метод стоит использовать тогда, когда нужно обеспечить выполнение некоего кода в самом начале следующей итерации цикла событий.
    setImmediate()
    Ещё одной функцией, предоставляемой Node.js для асинхронного выполнения кода, является setImmediate()​. Вот как ей пользоваться: setImmediate(() => {
    //выполнить некий код
    })
    Функция обратного вызова, переданная ​setImmediate()​, будет выполнена на следующей итерации цикла событий.
    Чем ​setImmediate()​ отличается от ​setTimeout(() => {}, 0)​ (то есть, от таймера, который должен сработать как можно скорее) и от ​process.nextTick()​?
    Функция, переданная ​process.nextTick()​ выполнится после завершения текущей итерации цикла событий. То есть, такая функция всегда будет выполняться до функции, выполнение которой запланировано с помощью ​setTimeout()​ или ​setImmediate()​.
    Вызов функции ​setTimeout()​ с установленной задержкой в 0 мс очень похож на вызов setImmediate()​. Порядок выполнения функций, переданных им, зависит от различных факторов, но и в том и в другом случаях коллбэки будут вызваны на следующей итерации цикла событий.

    Таймеры
    Выше мы уже говорили о функции ​setTimeout()​, которая позволяет планировать вызовы передаваемых ей коллбэков. Уделим некоторое время более подробному описанию её особенностей и рассмотрим ещё одну функцию, ​setInterval()​, схожую с ней. В Node.js функции для работы с таймерами входят в модуль ​
    timer​
    , но пользоваться ими можно, не подключая этот модуль в коде, так как они являются глобальными.
    Функция setTimeout()
    Напомним, что при вызове функции ​setTimeout()​ ей передают коллбэк и время, в миллисекундах, по прошествии которого будет вызван коллбэк. Рассмотрим пример: setTimeout(() => {
    // выполняется через 2 секунды
    }, 2000) setTimeout(() => {
    // выполняется через 50 миллисекунд
    }, 50)
    Здесь мы передаём ​setTimeout()​ новую функцию, тут же описываемую, но здесь можно использовать и существующую функцию, передавая ​setTimeout()​ её имя и набор параметров для её запуска. Выглядит это так: const myFunction = (firstParam, secondParam) => {
    //выполнить некий код
    }
    // выполняется через 2 секунды setTimeout(myFunction, 2000, firstParam, secondParam)
    Функция ​setTimeout()​ возвращает идентификатор таймера. Обычно он не используется, но его можно сохранить, и, при необходимости, удалить таймер, если в запланированном выполнении коллбэка больше нет необходимости: const id = setTimeout(() => {
    // этот код должен выполниться через 2 секунды
    }, 2000)
    // Программист передумал, выполнять этот код больше не нужно clearTimeout(id)
    Нулевая задержка
    В предыдущих разделах мы использовали ​setTimeout()​, передавая ей, в качестве времени, по истечении которого надо вызвать коллбэк, ​0​. Это означало, что коллбэк будет вызван так скоро, как это возможно, но после завершения выполнения текущей функции: setTimeout(() => {
    console.log('after ')
    }, 0) console.log(' before ')
    Такой код выведет следующее: before after
    Этот приём особенно полезен в ситуациях, когда, при выполнении тяжёлых вычислительных задач, не хотелось бы блокировать главный поток, позволяя выполняться и другим функциям, разбивая подобные задачи на несколько этапов, оформляемых в виде вызовов ​setTimeout()​.
    Если вспомнить о вышеупомянутой функции ​setImmediate()​, то в Node.js она является стандартной, чего нельзя сказать о браузерах (в IE и Edge она ​
    реализована​
    , в других — нет).
    Функция setInterval()
    Функция ​setInterval()​ похожа на ​setTimeout()​, но между ними есть и различия. Вместо однократного выполнения переданного ей коллбэка ​setInterval()​ будет периодически, с заданным интервалом, вызывать этот коллбэк. Продолжаться это будет, в идеале, до того момента, пока программист явным образом не остановит этот процесс. Вот как пользоваться этой функцией: setInterval(() => {
    // выполняется каждые 2 секунды
    }, 2000)
    Коллбэк, переданный функции, показанной выше, будет вызываться каждые 2 секунды. Для того чтобы предусмотреть возможность остановки этого процесса, нужно получить идентификатор таймера, возвращаемый ​setInterval()​ и воспользоваться командой ​clearInterval()​: const id = setInterval(() => {
    // выполняется каждые 2 секунды
    }, 2000) clearInterval(id)
    Распространённой методикой является вызов ​clearInterval()​ внутри коллбэка, переданного setInterval()​ при выполнении некоего условия. Например, следующий код будет периодически запускаться до тех пор, пока свойство ​App.somethingIWait​ не примет значение ​arrived​: const interval = setInterval(function() { if (App.somethingIWait === 'arrived') { clearInterval(interval)
    // если условие выполняется - удалим таймер, если нет - выполним некие действия
    }

    }, 100)
    Рекурсивная установка setTimeout()
    Функция ​setInterval()​ будет вызывать переданный ей коллбэк каждые ​n​ миллисекунд, не заботясь о том, завершилось ли выполнение этого коллбэка после его предыдущего вызова.
    Если на каждый вызов этого коллбэка всегда требуется одно и то же время, меньшее ​n​, то никаких проблем тут не возникает.
    Периодически вызываемый коллбэк
    ,
    каждый сеанс выполнения которого занимает одно и
    то же время
    ,
    укладывающееся в
    промежуток между вызовами
    Возможно, для выполнения коллбэка каждый раз требуется разное время, которое всё ещё меньше ​n​.
    Если, например, речь идёт о выполнении неких сетевых операций, то такая ситуация вполне ожидаема.
    Периодически вызываемый коллбэк
    ,
    каждый сеанс выполнения которого занимает разное время
    ,
    укладывающееся в
    промежуток между вызовами
    При использовании ​setInterval()​ может возникнуть ситуация, когда выполнение коллбэка занимает время, превышающее ​n​, что приводит к тому, что следующий вызов осуществляется до завершения предыдущего.
    Периодически вызываемый коллбэк
    ,
    каждый сеанс выполнения которого занимает разное время
    ,
    которое иногда не укладывается в
    промежуток между вызовами
    Для того чтобы избежать подобной ситуации, можно воспользоваться методикой рекурсивной установки таймера с помощью ​setTimeout()​. Речь идёт о том, что следующий вызов коллбэка планируется после завершения его предыдущего вызова: const myFunction = () => {
    // выполнить некие действия setTimeout(myFunction, 1000)

    } setTimeout( myFunction()
    }, 1000)
    При таком подходе можно реализовать следующий сценарий:
    Рекурсивный вызов
    setTimeout()
    для планирования выполнения коллбэка
    1   2   3   4   5   6   7   8   9


    написать администратору сайта