Неблокирующее асинхронное итерирование в JavaScript

  Рет қаралды 7,890

Timur Shemsedinov

5 жыл бұрын

Примеры кода: github.com/HowProgrammingWorks/NonBlocking
Курс «100 лекций по программированию» habr.com/post/427799/
#асинхронное #программирование #итерирование #лекции #javascript #кпи #js

Пікірлер: 27
@antontelichenko2102
@antontelichenko2102 2 жыл бұрын
1:02 блокирующее итерирование по массиву 3:24 блокирующее итерирование с помощью for await 4:47 неблокирующее итерирование с помощью setTimeout 6:45 неблокирующее итерирование с помощью for await 8:20 неблокирующее итерирование без задержки 13:00 неблокирующее итерирование без задержки с помощью for await 19:30 использование асинхронного итерирования для обычных массивов
@victorklimov5254
@victorklimov5254 3 жыл бұрын
Спасибо за крутейшие видео!
@vladimirpirogov1336
@vladimirpirogov1336 2 жыл бұрын
Тимур, очень нужная лекция, спасибо! Маленькая ремарка. Вы подробно рассказали "как", но не объяснили " почему". Думаю для большинства нас, "студентов", не очевидно, что async loop, используя промисы, узурпирует очередь микрозадач. Вы показываете, что setInterval позволяет периодически " вываливаться" в макрозадачи, где, вероятно, уже есть другие обработчики.
@user-bb7wi4lv6q
@user-bb7wi4lv6q 2 жыл бұрын
Удваиваю. Непонятно, за счёт чего именно происходит "неблокирование"?
@vitalaskompulat5053
@vitalaskompulat5053 2 жыл бұрын
@@user-bb7wi4lv6q надо доку читать там какие-то фазы есть у even loop-a - на одной фазе обрабатываются все callback-и на другой setTimeout-ы на третей processNextTick судя по всему из-за этого, но я сам до конца не разобрался
@kujojotaro3464
@kujojotaro3464 Жыл бұрын
@@vitalaskompulat5053 Колбеки из setTimeout падают в обычную очередь колбеков их подхватит Event-Loop как только освободится стек по очереди. Promise возвращают микротаски (отдельная очередь которая имеет приоритет над колбеками), тоесть если у тебя есть какой то промис который перешел в состояние resolve то его 'колбек' выполнится перед основной очередью колбеков. processNextTick выполняет таску на текущем круге event-loop тоесть у тебя очистился стек -> выполняется processNextTick -> новый круг event-loop -> микротаски(промисы) -> макротаски(колбеки + таймауты)
@artemmakhaydinov3586
@artemmakhaydinov3586 8 ай бұрын
@@kujojotaro3464 Спасибо за разъяснение! Я правильно понимаю, что данный цикл не будет блокировать любую микротаску, которая возникнет в том же процессе во время итерирования?
@olegborodko1801
@olegborodko1801 4 жыл бұрын
сложно пока-что для меня, но круто, как-раз нужен пример асинхронного перебора массива.. спасибо
@NVsquare
@NVsquare 5 жыл бұрын
О, это моя тема. Я у вас об этом в чатике спрашивал
@TimurShemsedinov
@TimurShemsedinov 5 жыл бұрын
И к какому решению мы пришли?
@NVsquare
@NVsquare 5 жыл бұрын
@@TimurShemsedinov ну типа декорировать нью промис сеттаймаутом
@TimurShemsedinov
@TimurShemsedinov 5 жыл бұрын
@@NVsquare Ну да, но тут бы хотелось это встроить в коллекции, лучше всего через такой преобразователь классов коллекций: unblock = AsyncIterableCollectionClass => NonBlockingAsyncIterableCollectionClass
@TimurSevimli
@TimurSevimli Жыл бұрын
Спасибо большое за лекцию, Тимур Гафарович! Возникает такой вопрос. Возможно, из-за отсутствия опыта, но я заметил, что когда я меняю setTimeout(fn, 0) на setImmediate, то скорость выполнения итераций повышается настолько, будто это синхронный код, но при этом он выполняется параллельно, и выводы next работают (например, в файле 4-for-non-blocking.js). Я задумался, стоит ли вместо использования хитростей, таких как отдавание времени в event loop с помощью интервалов, использовать setImmediate, что кажется гораздо проще. Аж настолько проще, что кажется, есть какой-то подвох, но я не могу додуматься, в чем он заключается. Я знаю, что setImmediate можно перебить с помощью других таймеров, так как setImmediate в каждом цикле event loop исполняется последним из всех таймеров. Получается, что можно использовать setImmediate, если одновременно не используются другие таймеры с большими задержками?
@ruslanglaznyov9117
@ruslanglaznyov9117 3 жыл бұрын
Спасибо за лекцию! А почему settimeout 0, а не setimmediate?
@vladimirpirogov1336
@vladimirpirogov1336 2 жыл бұрын
В 14:00 Вы говорите про spread оператор. Насколько вообще вменяемая идея разворачивать spread'ом async iterator в реальной жизни? Какие могут быть use-кейсы?
@calmnad
@calmnad 3 жыл бұрын
есть ли хорошие npm, реализующие типовые классы/методы с подобной "не блокировкой" выполнения?
@TimurShemsedinov
@TimurShemsedinov 3 жыл бұрын
Не знаю, напишите такую либу, можете взять код за основу, ссылку добавьте на меня )
@user-yu7gm4df3f
@user-yu7gm4df3f 3 жыл бұрын
интересные хитрости
@randomtron
@randomtron Жыл бұрын
Не совсем ясно, что происходит, когда внутри промиса (очередь микрозадач) вызывается таймер (другая очередь - макрозадачи). Мы сразу "перескакиваем" из очереди микрозадач в макрозадачи, т.к иначе коллбэк в промисе попросту не исполнится, или же всё ещё проще: в очереди микрозадач закончились коллбэки (в примере с 6-for-opt) и мы переходим к очереди макрозадач как обычно?
@user-vx9ug1nb2t
@user-vx9ug1nb2t 4 жыл бұрын
Здравствуйте Тимур. Очень нравятся ваши лекции, спасибо! Но я не могу разобраться с примером 6-for-opt.js. Как он работает мне ясно, но я попытался заменить значение value в объекте возвращаемом из метода next на this.start. У меня получился вот такой объект {value: this.start, done: this.start++ === this.end+ 1} и всё сломалось. Цикл стал выводить все значения по два раза, я никак не могу разобраться с чем это связано( Буду благодарен за ответ.
@victorklimov5254
@victorklimov5254 3 жыл бұрын
Скорее всего дело в потере контекста. Поясню. Если прямо непосредственно в методе @@asyncIterator объекта range написать console.log(this), то этот this укажет на range, поэтому this.start укажет именно на тот число, который мы имеем в виду. Но... Сам метод @@asyncIterator возвращает тоже объект, в котором уже есть метод next. Так вот если в методе next написать console.log(this), то это this уже укажет на этот внутренний объект, а не на range. А в этом внутреннем объекте поля start отсутствует и поэтому this.start вернет undefined. По этой же причине this.end тоже будет undefined. undefined++ станет NaN. undefined + 1 тоже NaN. И сравнение NaN === NaN вернет false. В результате: итератор отдает объект { value: 1, done: false } и значит цикл никогда не закачивается. У меня, по крайней мере так получается. Как Вы сделали, что цикл отрабатывает по два раза, подсказать сходу не смогу.
@karyapkin
@karyapkin Жыл бұрын
Мой ноутбук исполняет неблокирующие циклы неприлично долго - от 8000 до 10000 мс. Пробовал разные версии node - не влияет. Ноутбук на win, вроде процессор не слабый. Не понимаю почему такая большая разница с примером из видео у Тимура
@Wra-ij8yk
@Wra-ij8yk 7 ай бұрын
Генераторы для неблокирующее асинхронное итерирование не используются? Возможно есть примеры кода на гитхабе?
@TimurShemsedinov
@TimurShemsedinov 7 ай бұрын
Используются, например современные интерфейсы стримов это поддерживают
@Wra-ij8yk
@Wra-ij8yk 7 ай бұрын
​@@TimurShemsedinov, Я вот не понимаю будет ли код на генераторах блокирующим, как сделать не блокирующий код( yeld в калбэк передать нельзя). Есть догадки но асинк генератор в целом трудно проверить на то блокирующий ли он или нет. Скажите что думаете, возможно и смысла нет в использования генератора в таком коде. let range = { from: 1, to: 10000, async *[Symbol.asyncIterator]() { for(let value = this.from; value { for await (let value of range) { console.log(value); } })();
@Wra-ij8yk
@Wra-ij8yk 6 ай бұрын
Вот такое решение придумал: чтобы не блокировать макростаки const range = { start: 1, end: 10000, async *[Symbol.asyncIterator]() { for (let val = this.start; val setImmediate(resolve)); yield val; } } }; let k = 0; const timer = setInterval(() => { console.log('next ', k++); }, 10); (async () => { const begin = process.hrtime.bigint(); for await (const number of range) { console.log(number); if(number == range.end){ clearInterval(timer) } } const diff = (process.hrtime.bigint() - begin) / 1000000n; console.log('Time(ms):', diff.toString()); console.dir({ k }); })()
@erjigit17
@erjigit17 2 жыл бұрын
иногда мне кажется что вас много. Не может один человек проявлять такую активность ))
THEY WANTED TO TAKE ALL HIS GOODIES 🍫🥤🍟😂
00:17
OKUNJATA
Рет қаралды 9 МЛН
Я нашел кто меня пранкует!
00:51
Аришнев
Рет қаралды 1,5 МЛН