Defront — про фронтенд-разработку и не только
24.3K subscribers
21 photos
1.09K links
Ламповый канал про фронтенд и не только. Всё самое полезное для опытных web-разработчиков

Обсуждение постов @defrontchat

Также советую канал @webnya
Download Telegram
Прочитал небольшую статью Тори Волкера "The Pitfalls of Async/Await in Array Loops" про использование async/await в циклах.

По ходу статьи Тори рассказывает как добиться того, чтобы три промиса были выполнены по порядку с использованием циклов. В начале он показывает неправильно работающий пример с использованием forEach и объясняет, почему он не работает так как нужно (в комментариях есть больше подробностей). Потом показывает уже работающее решение с использованием map. В этом примере почти всё работает как ожидается, но промисы не ждут друг друга. В последнем примере используется for...of, с которым всё ок – каждый промис ждёт выполнения предыдущего.

Статья небольшая, но вполне адекватная. Если у вас в проекте используется async/await, то статья может быть вам полезна.

#js #async

https://medium.com/dailyjs/the-pitfalls-of-async-await-in-array-loops-cf9cf713bfeb
Пару дней назад разработчики Chrome твитнули про то, что реализация нового предложения в JS — Promise.allSettled — была добавлена в Chrome 76. Также поддержка нового предложения уже есть в ночных сборках Firefox.

Новая фича — это дополнение к уже существующему Promise.all(). Если all() прекращает работу как только любой из промисов возвращает reject, то allSettled() дожидается выполнения всех промисов и возвращает массив снапшотов состояния с результатами работы промисов вне зависимости от того были ли среди них промисы с reject.

В рамках текущего стандарта можно обработать все промисы подобно allSettled, если сделать дополнительную функцию (+обратите внимание на promises.map(reflect)):

function reflect(promise) {
return promise.then(
v => ({status: 'fulfilled', value: v }),
error => ({status: 'rejected', reason: error})
);
}

const promises = [fetch('good.html'), fetch('bad.html')];
const results = await Promise.all(promises.map(reflect));
const successfulPromises = results.filter(
p => p.status === 'fulfilled'
);


С использованием allSettled этот код становится гораздо проще:

co
nst promises = [fetch('good.html'), fetch('bad.html')];
const results = await Promise.allSettled(promises);
const successfulPromises = results.filter(
p => p.status === 'fulfilled'
);

Promise.allSettled() находится в stage 3. Это значит, что скорее всего он попадёт в стандарт либо в этом, либо в следующем году.

#js #proposal #async

https://github.com/tc39/proposal-promise-allSettled
Как-то я пропустил это небольшое событие. В январе появилось предложение Матиаса Байненса о добавлении в стандарт JavaScript нового метода промисов any().

Promise.any() сигнализирует о том, что один из обрабатываемых промисов был успешно разрешён. Этот метод похож на метод Promise.race(), но отличается тем, что не завершает работу, если был отклонён один из промисов. Отклонение Promise.any() происходит только тогда, когда все обрабатываемые промисы были отклонены. Вот небольшой пример, как работает этот метод:
const promises = [
fetch('/endpoint-a').then(() => 'a'),
fetch('/endpoint-b').then(() => 'b'),
fetch('/endpoint-c').then(() => 'c'),
];
try {
const first = await Promise.any(promises);
// Один из промисов был успешно разрешён, например 'b'
// При этом и 'a', и 'c' могли быть отклонены
console.log(first);
} catch (error) {
// Все промисы были отклонены
console.log(error);
}


Предложение находится на первом этапе рассмотрения в TC39. И я пока не вижу причин, почему его могут выкинуть из стандарта.

UPD: Только что обнаружил, что соавтор предложения Сергей Рубанов — ведущий канала @juliarderity (спецификации и другие горячие новости из мира web).

#js #proposal #async

https://github.com/tc39/proposal-promise-any
Сегодня меня занесло в 2015-ый год. Прочитал статью Джека Арчибальда про старые баги браузеров с планированием микрозадач — "Tasks, microtasks, queues and schedules".

Если выполнить такой код:
console.log('script start');
setTimeout(() => console.log('setTimeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('script end');


то в консоль будет выведено: "script start", "script end", "promise", "setTimeout". Такой порядок объясняется тем, что очередь микрозадач (куда попадают выполнение коллбеков MutationObserver и коллбеки промисов) опустошается до выполнения следующей задачи, которая в данном случае создаётся с помощью setTimeout.

В статье описываются ситуации, когда обработка микрозадач обрабатывалась браузерами по-разному. Например, при обработке коллбеков MutationObserver и Promise в рамках одной задачи.

Проверил примеры — браузеры уже пофиксили описанные проблемы. Но всё равно рекомендую почитать статью, если она прошла мимо вас.

#async #history

https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
Пару дней назад в код v8 была добавлена реализация предложения "Top-level await" (Stage 3). Про этот пропозал в канале ещё ничего не было, поэтому хочу написать небольшое объяснение того, какую проблему он решает.

Top-level await добавляет поддержку await на верхнем уровне модуля, то есть вне асинхронных функций, которые декларируются с помощью async. Это позволяет превратить модуль в некое подобие большой асинхронной функции. При импорте такого модуля асинхронный код, помеченный с помощью ключевого слова await, будет останавливать выполнение импортирующего модуля до того момента, пока все зависимости не будут зарезолвлены. Вот пример преобразования "асинхронного модуля" с помощью top-level await:

// было
import { process } from "./some-module.mjs";
export default (async () => {
const dynamic = await import(computedModuleSpecifier);
const data = await fetch(url);
const output = process(dynamic.default, data);
return { output };
})();

// стало
import { process } from "./some-module.mjs";
const dynamic = import(computedModuleSpecifier);
const data = fetch(url);
export const output = process((await dynamic).default, await data);


Добавление в стандарт top-level await упростит работу с динамическими импортами и модулями, предоставляющими асинхронные ресурсы, например, соединение с базой данных.

#future #async #tc39

https://github.com/tc39/proposal-top-level-await
В блоге Акселя Раушмайера пару дней назад появилась статья про использование асинхронных итераторов со стримами в Node.js — "Easier Node.js streams via async iteration".

Код, который агрегирует поступающие данные из readable stream или, наоборот, записывает данные во writable stream может быть записан компактно, используя возможности асинхронных итераторов (ES2018). Вот пример из статьи. В нём с помощью конструкции for await ... of считывается текст из readable stream и записывается в переменную result:
async function readableToString(readable) {
let result = '';
for await (const chunk of readable) {
result += chunk;
}
return result;
}


Выглядит очень элегантно. В статье ещё есть хороший пример трансформации стримов с помощью асинхронных генераторов.

В общем, рекомендую почитать, даже если не работаете много с Node.js.

#js #nodejs #async

https://2ality.com/2019/11/nodejs-streams-async-iteration.html
Александр Сурма рассказал про свой опыт использования WHATWG Streams для реактивного программирования — "Streams for reactive programming ".

WHATWG Streams — низкоуровневый примитив web-плафтормы, который решает проблему эффективной работы с I/O. Он лежит в основе Fetch API. В статье разбирается эксперимент использования стримов для создания observable-like библиотеки observables-with-streams (ows) и полноценного приложения на его основе. Эксперимент удался, но вскрыл проблему: в отличие от обычных observable подписчики в ows всегда выполняются асинхронно.

Не думаю, что появление ows заставит кого-то отказаться от Rx.js, но сам по себе эксперимент получился интересный. Рекомендую почитать статью, если хотите узнать побольше про использование WHATWG Streams и особенности реализации observable.

#async #streams #expeimental

https://dassur.ma/things/streams-for-reactive-programming/
Алан Сторм опубликовал статью про асинхронные генераторы и итераторы — "Async Generators and Async Iteration in Node.js".

Асинхронные итераторы используются вместе с асинхронными генераторами, которые возвращают промисы. Они очень полезны при обработке таких операций, которые возвращают значения порциями с течением времени. Их можно использовать со стримами, при работе с асинхронными API в браузере. На сайте Deno есть пример использования асинхронных итераторов для создания простого web-сервера:

import { serve } from "https://deno.land/std@0.50.0/http/server.ts";

for await (const req of serve({ port: 8000 })) {
req.respond({ body: "Hello World\n" });
}


Очень рекомендую почитать статью, если не приходилось работать с асинхронными итераторами ранее. В статье очень хорошо объясняется суть их работы.

#js #async

https://alanstorm.com/async-generators-and-async-iteration-in-node-js/
Использование AbortController и AbortSignal в Node.js

Джеймс Снелл — контрибьютор Node.js — написал статью про использование AbortController и AbortSignal в Node.js — "Using AbortSignal in Node.js".

Последние два года разработчики Node.js работают над добавлением разных API web-платформы. Результатом этой работы стала реализация AbortController, который появился в стабильной версии Node.js 16.

AbortController и AbortSignal реализуют интерфейс для отмены выполнения асинхронных операций. С его помощью можно прерывать таймеры, асинхронные запросы, отписываться от событий, добавленных с помощью интерфейса EventTarget, который поддерживают некоторые API Node.js. В статье рассказывается о том как использовать AbortController и AbortSignal на примере прерывания асинхронного события по таймауту.

Рекомендую почитать статью всем, так как AbortController доступен не только в Node.js, но и во всех актуальных браузерах.

#nodejs #async #api

https://www.nearform.com/blog/using-abortsignal-in-node-js/
Поиск необработанных промисов

Свизек Теллер написал статью про ошибки, приводящие к возникновению необработанных промисов — "Finding unresolved promises in JavaScript".

Необработанные промисы — это большой источник проблем, который может привести к крешу программы. Они возникают при забытом перехвате исключения с помощью catch, при отсутствующем вызове resolve / rejet или при забытом return в цепочке промисов.

Свизек нашёл научную статью "Finding broken promises in asynchronous JavaScript programs", в которой авторы попробовали автоматизировать поиск подобных ошибок и создали утилиту PromiseKeeper. Идея интересная, но похоже, что работу над проектом остановили после публикации статьи.

#async #js #experimental

https://swizec.com/blog/finding-unresolved-promises-in-javascript/