Каков наилучший способ/шаблон для выполнения последовательных операций в JS (NodeJS)? Например. Создать папку->копировать файл->редактировать файл->и т.д. Это автономное приложение, поэтому блокировка потоков допустима (синхронизация).
Не совсем уверен, что вопрос здесь. Если это отдельное приложение, то просто используйте sync
версии операций fs, которые вы уже знаете.
Не. Заведите привычку писать асинхронный код в узле повсюду, даже если в этом нет необходимости. Это просто хорошая практика, предотвращает рефакторинг кучи вещей в будущем, а с современным JS просто написать:
import { mkdir, copyFile } from 'fs/promises';
async function createThing() {
await mkdir('/path/to/dir');
await copyFile(src, dest);
...
}
Нет абсолютно никаких причин избегать синхронизирующих версий операций fs, когда это автономное служебное приложение, а не сервер (как говорит ОП). Использование асинхронных версий, когда нет никаких преимуществ, просто делает код более сложным, чем необходимо.
@jfriend00 — «сложнее, чем необходимо» — LMAO. Добавление слова await
затрудняет чтение. И есть всегда преимущество в том, что это нулевые дополнительные усилия, часто нетривиальные усилия по рефакторингу, и мы, как разработчики, сосать предсказываем, для чего они собираются использовать вещи в будущем. Просто войдите в привычку и избавьте себя в будущем от боли.
В чем разница между await mkdir() и mkdirSync()?
Это делает вызывающий код асинхронным, как и вызывающий код. Теперь его нужно дождаться. Если это обратный вызов .map()
или что-то в этом роде, вам нужно использовать Promise.all()
и т. д. Если это файл, к которому также может получить доступ другой код, запускаемый событием, вам нужно беспокоиться о нескольких путях кода, конкурирующих за тот же файл и т.д.
Хотя async/await
, безусловно, проще, чем то, что у нас было раньше, во многих отношениях это не так просто, как синхронный ввод-вывод, когда синхронный ввод-вывод можно использовать. Если вы хотите никогда не использовать синхронный ввод-вывод везде, не стесняйтесь, но для того, что делает OP (одно пользовательское служебное приложение), я бы рекомендовал синхронный ввод-вывод.
@DanielRay — await fs.promises.mkdir()
приостанавливает текущую async
функцию и немедленно возвращает вызывающему объекту невыполненное обещание. Если вызывающая сторона не ожидает этого обещания, вызывающая сторона продолжит выполнение другого кода (что может быть преимуществом или недостатком в зависимости от обстоятельств). Точно так же цикл обработки событий может обрабатывать и другие события (таймеры, сетевые события, завершение ввода-вывода и т. д.). Если вы используете fs.mkdirSync()
, он блокирует все, поэтому ничего не выполняется, пока эта функция не завершится. Это заставляет последовательное выполнение всего.
@DanielRay. Обратите внимание, что await fs.mkdir()
не является ни рыбой, ни птицей, поскольку await
ничего не делает, потому что fs.mkdir()
не возвращает обещание (ничего не возвращает). Чтобы использовать await
, используйте await fs.promises.mkdir()
. Кроме того, обработка ошибок различается для всех трех версий. fs.promises.mkdir()
отклоняет обещание, которое он вернул. fs.mkdir()
отправляет аргумент err
обратному вызову, который вы ему предоставили, а fs.mkdirSync()
выдает исключение.
Конечно, если у вас есть конкретное желание параллельного выполнения операций ввода-вывода, то варианты асинхронного ввода-вывода обеспечат это. Вопрос здесь был именно о том, как добиться последовательного ввода-вывода, а не параллельного.
Просто используйте async
/await
для последовательных асинхронных операций. Не нужно писать код синхронизации, о котором вы потом пожалеете. Кроме того, в зависимости от приложения вы можете получить тривиальные возможности ускорения, выполняя действия одновременно.
Тогда просто синхронизируйте вызовы. Я не знаю ни одного шаблона проектирования для этого. Кажется, вы просто хотите написать код, который вы описали, и все.