Тёмный

Макро и Микро задачи в JavaScript  

Easy IT
Подписаться 2,7 тыс.
Просмотров 10 тыс.
50% 1

Опубликовано:

 

21 окт 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 58   
@alexr0v
@alexr0v Год назад
я еще не встречал более сложного, запутанного и непонятного объяснения. Видео сохранил, буду им пугать кого-нибудь)) спасибо!
@EasyITChannel
@EasyITChannel Год назад
:) смешно, спасибо за просмотр
@---Maksim---
@---Maksim--- Год назад
Отличные примеры, с удовольствием посмотрел :) Спасибо!
@EasyITChannel
@EasyITChannel Год назад
Спасибо за поддержку, приятно когда время потрачено не зря :)
@АлександрСергеевич-и4ы
последний пример как раз спрашивали на собесе, про блок отрисовки
@АндрейРосовский
Я в ивент-лупе вроде как разбираюсь и с микро и макро тасками тоже давно решил вопрос. Просто интересно было взглянуть на твой ролик. Увидел необычный пример с вызовом тасок по клику, стало интересно взглянуть на остальные ролики и блин мужик, спасибо тебе огромное! Очень интересный контент! Однозначно подписка!=)
@EasyITChannel
@EasyITChannel Год назад
Спасибо за добрые слова и за поддержку, есть стимул двигать дальше.
@klierik
@klierik Год назад
Очень познавательное видео. Спасибо большое автору!
@johnstrayk5208
@johnstrayk5208 Год назад
Если идея была сделать простое сложным, то отлично получилось.
@EasyITChannel
@EasyITChannel Год назад
Спасибо за просмотр.
@buries_r
@buries_r Год назад
😁
@gregdmitriev2784
@gregdmitriev2784 Год назад
круто объяснил, спасибо
@АлександрСергеевич-и4ы
top
@ЗапискиЮногоПрогера
Очень рад что нашел твой канал, лайк за контент
@Dimidrol14
@Dimidrol14 Месяц назад
Посмотрел видос - еще больше запутался
@EasyITChannel
@EasyITChannel Месяц назад
Так бывает. Особенно когда и изначально четкого понимания не было, а были догадки навеянные знанием как это устроено в других языках. Более новое видео посмотрели?
@Valentin_I
@Valentin_I 2 года назад
Спасибо
@orucqarayev4759
@orucqarayev4759 Год назад
ты гений, спасибо!
@EasyITChannel
@EasyITChannel Год назад
Спасибо за просмотр :)
@MS-wh8ky
@MS-wh8ky Год назад
Спасибо огромное за видео! Подскажите, пожалуйста, а что будет в случае, если мы напишем setTimeout(() => console.log("Macrotask"), 1000); fetch(someUrl).then(() => console.log("Microtask")); Предположим, что fetch отработает в один момент с setTimeout. Перед выполнением произойдет первая перерисовка интерфейса, следовательно, весь основной код выполнится и добавятся одновременно в Macrotask queue console.log("Macrotask") и в Microtask queue console.log("Microtask"). Неужели в данном случае первым выполнится callback из setTimeout : console.log("Macrotask"), а только после него - console.log("Microtask") из fetch, так как исходя из видео сначала выполняется только одна задача из Macrotask queue (в нашем случае console.log("Macrotask")), а потом все задачи из Microtask queue (console.log("Microtask"))? Заранее благодарю за ответ!
@EasyITChannel
@EasyITChannel Год назад
Если «одновременно» (чего а реальной жизни не добиться) то именно так. Сначала вызовется на выполнение код одного макротаска, а потом вызовутся обработчики промисов для всех уже выполненных микротасков. В этом разница. Микротаск выполняется как бы параллельно и когда он уже выполнился происходит вызов обработчика промиса. Именно поэтому результат работы микротасков можно обрабатывать пачками - мы имеем дело с уже выполненной работой, поэтому это легкая задача.
@EasyITChannel
@EasyITChannel Год назад
Еще более просто постараюсь написать чтобы избежать путаницы. Порядок такой. Выполняется код одного макротаска, получаем результаты работы всех уже выполненных в фоне микротасков, перерисовываем страницу. Пока выполняется макротаск перейти на следующий шаг нельзя, но код микротасков при этом работает. Если к моменту завершения работы кода макротаска есть уже выполнившиеся микротаски то мы сможем их обработать. Но не раньше завершения макротаска. Микрозадача может выполниться очень быстро, но мы об этом не узнаем до тех пор пока не завершится текущая макро задача.
@MS-wh8ky
@MS-wh8ky Год назад
@@EasyITChannel спасибо!
@vladostema
@vladostema 2 месяца назад
Музычка зачет
@juliakorolenko6110
@juliakorolenko6110 Год назад
Мне осталось не понятным - почему обработчик из fetch попадает в макрозадачу, ведь под его капотом используется промис? Почему тогда промис и фетч отрабатывают по разному?
@EasyITChannel
@EasyITChannel Год назад
Когда зарезолвиься промис то это будет микротаск. Любой промис, хоть через fetch, хоть через new Promise- это микро задача. Значит выполнится после той макрозадачи во время которой зарезолвилось. Запомнить очень просто. Одна макрозадача, потом все зарезолвившиеся на данный момент микрозадачи, потом ререндер. И т. д. с начала :)
@juliakorolenko6110
@juliakorolenko6110 Год назад
@@EasyITChannel Спасибо!
@EasyITChannel
@EasyITChannel Год назад
Вы немного не в теме. Nodejs и js в браузере это разное. В браузере нет отдельно работающего независимого «основного» потока. Есть мэйн луп, это да. Берет макротаск из очереди выполняет, берет все ЗАРЕЗОЛВИВШИЕСЯ на этот момент микротаски (не все что есть) и выполняет по очереди, делает ререндер. Если в макротаске создать микротаск, который сразу зарезолвлен, то он выполнится сразу после текущего макротаска, если не зарезолаился еще то выполнится позже ПОСЛЕ какого-то другого макротаска. В js нет многопоточности и многопроцессности, нет прерываний. Все работает в одном потоке последовательно. Если что-то запустили, не важно микро или макро таск, он выполнится строго в свою очередь. Это легко проверить на практике, но кто сейчас проверяет? Проще верить в чудеса.
@АндрейРосовский
@@EasyITChannel Не понятно тогда, почему в консоли "promise-4" и "MICRO" идут перед "macro-2"(как и полагается микротаскам), а вот микротаска "promise fetch" идёт после? Ведь "promise fetch" тоже микротаска. Или тут дело в том, что "promise-4" резолвится сразу без ожидания, а "promise fetch" ждёт ответа сервера, и мол, пока сервер отвечает в ивент-луп попадает макротаска "macro-2"?
@---Maksim---
@---Maksim--- Год назад
@@АндрейРосовский Fetch API попадает в очередь макрозадач, а вот его обработка(любая обработка промиса) попадает уже в очередь микрозадач. Стоит запомнить, что Web API - это все макротаски.
@johnkucharsky6927
@johnkucharsky6927 3 месяца назад
Для тех кто не понял почему setTimeout в 3 примере работает так медленно, там задержка ноль это на самом деле около 4мс, поэтому проц не нагружается
@EasyITChannel
@EasyITChannel 3 месяца назад
Не верно. То что у тайм-аута с нулевой задержкой на самом деле есть реальная задержка в 4мс в данном случае не является причиной. Причина именно такой последовательности срабатывания обработчиков в том, что setTimout создает кроме задержки еще и макротаск. То есть сначала будет задержка на указанное время, а потом функция попадет в очередь макротасков и выполняется по обычным правилам event loop. «Проц» при этом нагружается абсолютно также, просто между отдельными макрозадачами происходит отрисовка интерфейса и пользователю кажется что нет подвисаний как если бы тоже самое делалось в while(true) цикле. Внимательно пересмотрите видео, Вы просто ничего не поняли. За деревьями не увидели леса.
@johnkucharsky6927
@johnkucharsky6927 3 месяца назад
@@EasyITChannel получается что отрисовка каждые 100 по счетчику, а не всё сразу. Это понятно. Но если бы не задержка на сеттаймаут, цикл прошёл бы очень быстро и всё бы зависло. Когда вы стали менять условия в цикле, в конце видео, зависания, доказывают это
@johnkucharsky6927
@johnkucharsky6927 3 месяца назад
Я про то что цикл проходит моментально, он не должен так долго считать
@EasyITChannel
@EasyITChannel 3 месяца назад
Дело не в этом. Чтобы понять в чем причина нужно просто понимать как работает эвент луп (данный ролик как раз об этом). Все довольно просто, не нужно ничего предполагать или придумывать. Например, счетчики. 1. выполняется один макротаск из очереди 2. выполняются обработчики ВСЕХ зарезолвленных микротасков 3. выполняется перерендер UI. 4. переход к пункту 1. Если макротаска нет (представьте, такое бывает), то вызывается обработчики зарезолвленных микротасков (промисов) и т.д. по кругу Сет таймаут с любой задержкой создает макротаск. Функция-обработчик это тело макротаска. Обработчик попадет в очередь после задержки, указанной для сетТаймаут. Пока висит таймаут с этой задачей ничего не происходит. Когда таймаут завершится функция попадет в очередь макротасков как отдельный макротаск. В нашем случае, если задать сетТаймаут 0, то эта функция попадет в очередь сразу и кроме того это гарантированно приведет к тому, что функция сработает ПОСЛЕ как минимум одного ререндера. Но если функция в сетТаймауте будет тяжелая, то на время ее выполнения все зависнет, т.к. это макротаск. Пока он работает к ререндеру JS перейти не может. Именно поэтому и висит, и разгрузка происходит не потому, что у таймаута маленькая задержка (или большая) а потому, что это новый макротаск. Улавливаете? Смысл совсем в другом, не в задержке. Сама по себе задержка ничем не поможет. Если просто завесить макротаск с помощью while(true), то и UI зависнет до его завершения.
@johnkucharsky6927
@johnkucharsky6927 3 месяца назад
@@EasyITChannel теперь понял, спасибо за очень подробное объяснение. Недавно провалил 2 собеседования, одно в вк, другое в уралсиб. Теперь вот изучаю всё, чтобы в следующий чтобы пройти. Про микро и макротаски спрашивали и там и там. В вк еще надо было полифил для Promise.all написать, то есть надо знать всё методы js, уметь написать самому. Ну и всё что на learnjavascript, надо знать, прям хорошо. Не считая regex конечно
@romandeveloper7720
@romandeveloper7720 Год назад
Эммм!!! Микрозадачи приоритетнее макрозадач! Сначала выполняются все микро, потом макро по одной
@EasyITChannel
@EasyITChannel Год назад
Нет, сначала выполнится макрозадача, в которой создали микрозадачи, потом все зарезолвившиеся микрозадачи, потом перерендер, потом следующая макрозадача. Тут нет приоритетов, увы, js однопоточный язык
@АндрейЛ-щ3э
@АндрейЛ-щ3э Год назад
@@EasyITChannel ну если взять в файлике создать несколько промисов, затем нес колько сеттаймаутов, то сперва отработают промисы, затем сеттаймауты. Что то на подобии: Promise.resolve().then(()=>console.log("in promise1")); setTimeout(()=>{ console.log('in setTimeout1') }, 0); setTimeout(()=>{ console.log('in setTimeout2') }, 0); setTimeout(()=>{ console.log('in setTimeout3') }, 0); setTimeout(()=>{ console.log('in setTimeout4') }, 0); setTimeout(()=>{ console.log('in setTimeout5') }, 0); setTimeout(()=>{ console.log('in setTimeout6') }, 0); Promise.resolve().then(()=>console.log("in promise2")); Promise.resolve().then(()=>console.log("in promise3")); Promise.resolve().then(()=>console.log("in promise4")); Promise.resolve().then(()=>console.log("in promise5")); То вывод будет: in promise1 in promise2 in promise3 in promise4 in promise5 in setTimeout1 in setTimeout2 in setTimeout3 in setTimeout4 in setTimeout5 in setTimeout6
@EasyITChannel
@EasyITChannel Год назад
Все верно. Все написанное выполняется в макротаске. В нем Вы создаете уже зарезолвившиеся промисы и другие макротаски. Как только текущий макротаск завершится начнут выполняться все зарезолвившиеся микротаски, потом ререндер, потом следующий (один) макротаск, опять все зарезолвившиеся микротаски, опять ререндер и т. д. Вы (не конкретно Вы лично) всё время забываете о том, что сам выполняемый код это тоже макротаск. Не будет прерывания его работы, нет никаких приоритетов. Поставьте в коде консоль логи после каждого вызова и вы увидите, что код выполнится полностью, то есть завершится текущий макротаск, а уже потом пойдут сообщения из промисов. Почему так, если у микротасков высокий «приоритет»? Ответ прост- нет приоритетов. Программа выполняется последовательно по определенной логике. Код микротаска выполняется асинхронно, но получить его результат можно только последовательно, после таска, во время которого он зарезолвился. Именно поэтому можно обработать пачку микротасков - они уже посчитались, нужно только забрать результат, это быстро.
@aleksandrkim550
@aleksandrkim550 Год назад
16:00 лучше использовать request requestAnimationFrame. А разве он не вызывается не чаще чем 1сек/60?
@EasyITChannel
@EasyITChannel Год назад
Дело тут вот в чем. 1. setTimeout, особенно с нулевой задержкой очень часто приводит к лишним вычислениям, т.к. вызов колбеков привязан только ко времени задержки, но мало связан с тем успел браузер реально отрисовать сцену или нет 2. setTimeout вызвается всегда, даже если отрисовывать страницу не нужно (браузер свернут, вкладка не активна) 3. requestAnimationFrame не просто вызывает колбек как можно чаще, но и оптимизирует вызов с точки зрения браузера, что позволяет расходовать ресурсы более рационально. Как результат fps обычно выше, при одинаковых входных условиях. Отрисовка становится более плавной, исключаются ненужные ре-рендеры. 4. requestAnimationFrame не выполняет отрисовок в фоне. Общий вывод из этого такой - если имеем дело с анимацией, то лучше делать выбор в пользу requestAnimationFrame. 60 fps это не мало. Не нужно забывать, что это браузер, а не шутер на нативном движке. Хотя и там 60 fps очень даже не плохой результат.
@aleksandrkim550
@aleksandrkim550 Год назад
@@EasyITChannel может я что то не понимаю. В моей голове это так. С requestAnimationFrame Отрисовка. Ожидание . шаг в 100 итераций. Отрисовка. Ожидание. Ещё 100. Отрисовка. С setTimeout. Отрисовка. Столько шагов сколько успеет. Отрисовка. Столько шагов сколько успеет. Получается что черрз timeout можно быстрее массив обойти. Но я так понимаю что если setTimeout запустится и не успеет завершится то отрисовка будет ждать его конца
@EasyITChannel
@EasyITChannel Год назад
очень грубо - requestAnimationFrame вызывается когда надо что-то перерисовать и предыдущая отрисовка полностью закончилась, через сетТаймаут создается обычный макротаск, который будет вызван минимум после следующего рендера (это если delay=0) и пока он не завершится отрисовки не будет. В этом случае массив обойти можно, но если это займет много времени, то юзер заметит подвисание интерфейса (потерю отзывчивости). Это раз, а два, если обход массива будет происходить очень быстро, то легко может сложиться ситуация когда макротаск закончился, а предыдущая анимация еще не завершилась (не путать с отрисовкой, ре-рендером) и получается что уже новые макротаск + ре-рендер, а результат вычисления не отличается от предыдущего. Выходит лишняя нагрузка на браузер, лишние перерендеры, когда они и не нужны. Макротаски с работой отрисовки связаны только тем, что выполняются последовательно. Тут есть и обратная сторона медали. Многие думают, что чем выше фпс нем круче. Это не всегда верно. Если это 3Д шутер - обычно да. Но не всегда. Это классическое, увы, заблуждение от непонимания смысла. Если сцена совсем не меняется нет смысла вообще делать ре-нердеры. Они нужны только при каких-то изменениях. Если на экране в центре черный квадрат и он не двигается и юзер ничего не делает, нет смысла этот квадрат перерисовывать с частотой 60фпс. Можно один раз перерисовать и все. Это даже не 1фпс, а 1 фп вечность. :) Вот если он двигается, тогда другое дело. И то зависит от скорости перемещения. Если медленная, то и фпс можно уменьшить, нет смысла делать кучу вычислений, когда они не нужны. В этом случае может как раз сетТаймаут зайти, если колбэк быстрый. Или requestAnimationFrame с проверкой времени прошедшей с предыдущего вызова и запуском обработки реже чем вызывается сам колбек.
@EasyITChannel
@EasyITChannel Год назад
По поводу "с сетТаймаут - Отрисовка. Столько шагов сколько успеет..." Нет, с сетТаймаут так - вызов сетТаймаут с передачей с него колбек функции создает новый макротакс. Затем получение результатов всех зарезолвившихся микротасков. Затем отрисовка. ... Вызов колбек функции созданного ранее макротаска. Пока эта функция не завершится на следущий шаг не перейти. Если колбэк выполнняется 1 минуту, то на 1 минуту интерфейс зависнет. когда завершится колбэк сетТаймаута сработают по очереди обработчики для получения результатов работы микротасков. После этого произойдет следующая отрисовка.
@---Maksim---
@---Maksim--- Год назад
@@EasyITChannel есть нюанс. setTimeout тоже неточная функция и также имеет idle состояния как раз когда, например, вкладка неактивна и др., именно поэтому таймеры на setTimeout и setInterval - это неточные функции, они не подойдут для того же приложения "таймер", например, там требуется делать компенсацию задержки из-за неточности.
@РусланА-ф2н
@РусланА-ф2н Год назад
Огромное спасибо! Всё доступно и понятно
@alexeyser
@alexeyser Год назад
Страшные слова какие-то: сначала выполняются макрозадачи, потом микро😵‍💫 Это равносильно, что сеттаймаут выполнится первее, чем промис?
@EasyITChannel
@EasyITChannel Год назад
Добрый день :) Вы не внимательно смотрели видео, услышали что-то что рушит уже привычную картину мира и сразу спорить. Сначала вызывается обработчик завершенного к данному моменту макро задачи, затем вызываются все ОБРАБОТЧИКИ завершенных к данному моменту микрозадач. Так происходит потому, что обработчики микрозадач вызываются тогда, когда сам промис УЖЕ зарезолвился, т.е. основная длительная работа сделана и нужно только забрать готовый результат. Функция тела промиса выполняется в отдельном потоке параллельно, но забрать результаты работы промиса можно только в основном потоке поэтому так и сделано. Толку с того, что промис выполнился супер быстро, если к Вам данные попадут только в тот момент, когда вызовется обработчик? В данном видео речь идет как раз об обработчиках, потому что это единственное с чем разработчик может взаимодействовать. Поэтому да, так и будет, если предположить, что время выполнения сет таймаута и тела промиса завершатся одновременно, то сначала сработает функция переданная в таймаут, а уже потом функция переданная в then. Верить мне на слово не нужно, именно поэтому тут кроме разговоров о высоком есть еще код.
@alexeyser
@alexeyser Год назад
Хорошо, выполняться они могут и одновременно, а как вывестись результат сеттаймаута может быстрее, если он сперва смотрит пуста ли очередь микрозадач,и если да, то закинет макро. Или в ответе имелось в виду, что сет сработает до того, как в очередь микротасок промис попадёт?
@EasyITChannel
@EasyITChannel Год назад
Нет, Вы не правы. Работает мэйн луп не так. 1. Проверяет есть ли в очереди макротаск, если есть выполняет его. На время выполения маротаска мэйн луп как бы зависает, не будет в том числе и перерисовки UI, не будет вызовов обработчиков промисов. Это легко проверить. 2. После завершения макротаска проверяет есть ли УЖЕ РАЗЕРЗОЛВЛЕННЫЕ (не находящиевся в очереди, нет!!!) микротаски, если есть - выполняет обработчики их всех. Обычно это быстрое действие, т.к. работа микротасков сделана в бэкграунде и нужно толко забрать результат. 3. Выполняется перерисовка UI 4. Переход к пункту 1. Есть подозрение, что Вы знаете какой-то другой язык кроме JS, в котором есть реализация мультипоточности поэтому происходит искажение восприятия JS. Напомню - JS язык однопоточный. Да у него есть механизмы типа промисов и сервис воркеров, но на общую картинку (см. main loop) это влияет не очень сильно. Все что написано выше проверено опытным путем на практике, если посмотреть это видео, там как раз об этом. Не хочу Вас обидеть, но в этом заблуждении Вы далеко не одиноки. Меня удивляет только то, почему так много разработчиков верят в то, что легко опровергается на практике.
@denmccormik7654
@denmccormik7654 2 года назад
Спасибо, очень полезное видео Не хочу показаться глупым, но хочу задать вопросы 1. Функции которые не являются ни микрозадачами, ни макрозадачами мы называем синхронными? 2. Если js встречает сначала макрозадачу тайм-аут 0, а после микро - промис. Сначала произойдет микрозадача, а потом макро. Вот для каких случаев верно утверждение из видео, что выполняется одна макрозадача, а после все микрозадачи? Потому что сначала сработает промис и потом тайм-аут. И до этого видео я уверенно так и думал, приоритет - микрозадачи, после макро
@EasyITChannel
@EasyITChannel 2 года назад
Вопросы очень правильные. Спасибо. 1. Любая синхронная функция вызывается в рамках или микрозадачи или макрозадачи. Обычно макро. Любой скрипт является макрозадачей, любая функция обработчик события тоже. Веб воркеры тут не рассматриваем, по этой теме будет отдельное видео. 2. Макро задача размещается в момент вызова функции таймаута, не в момент создания таймаута. Аналогично промис размещает обработчик в очереди микрозадач в момент срабатывания метода then, catch, finally и других. Не в момент создания промиса. Вот и получается. Наш код выполняется в какой-то макрозадаче (даже если в теге что-то написать, то это будет макрозадача) и в этой макрозадаче мы создаем еще одну макрозадачу через таймаут с задержкой 0 (на самом деле это будет в районе 4мсек) она попадает в очередь, но вызовется только после ближайшего перерендера. Это если в очереди других макрозадач нет. Когда завершится текущая макрозадача, то JS начнет извлекать все доступные в данный момент микро задачи, все что есть в очереди, и выполнять по очереди. После этого произойдет перерендер и уже потом JS возьмет следующую макрозадачу из очереди макрозадач (ту что мы создали с таймаутом 0). Вобщем если мы создаем макрозадачу через setTimeout, то функция обратного вызова сработает как минимум после ближайшего перерендера. Если же мы создаем уже зарезолвленный пропис - то он попадет в очередь микрозадач уже во время работы текущей задачи и после ее завершения будет обработан.
@denmccormik7654
@denmccormik7654 2 года назад
@@EasyITChannel Ещё раз спасибо, очень доходчиво и понятно. Буду ждать тогда видео по сервис / веб воркерам
@zergzerg4844
@zergzerg4844 8 месяцев назад
@@EasyITChannel То есть ,все функции задекларированные в коде не беря в расчет setTimote и промисы , являются макрозадачами , а то что внутри выполнятеся это микро - задачи? Типа doit =(text) => console.log(text) doit - макро-таска, а console.log(text) - микро-таска, а если поместить в setTimote doit =(text) => setTimote () , то setTimote уже будет -макро-таской помещенной в очередь-вызовов и выполнится после предыдущей макро-таски. Я правильно понял?
@johnkucharsky6927
@johnkucharsky6927 3 месяца назад
Console.log это не макро. Автор сам не разобрался до конца. Но пример интересный
@EasyITChannel
@EasyITChannel 3 месяца назад
Это очень смешное утверждение. Примерно как - надпись на заборе это не забор. Вам нужно для начала научиться слушать и понимать услышанное. При необходимости пересмотреть несколько раз, а уже потом высказывать умные мысли. Конечно, Вы легко сможете указать место, где автор сказал, что консоль лог это макротаск. :)
Далее
1 Subscriber = 1 Penny
00:17
Просмотров 49 млн
1 Subscriber = 1 Penny
00:17
Просмотров 49 млн