Геть callback hell або як працюють promises Santa Simplicita
Просто писати про просте — не так просто…
Геть callback hell або як працюють promises?
Піст буде недовгим. Всі хто писав на джаваскрипті (особливо під Node.js) знають, що мова це однопоточна, і будь-які тривалі (блокуючі) операції зазвичай оформлюють у функції такого виду:
Відповідно, якщо потрібно виконати кілька дій поспіль послідовно, виходить некрасива конструкція:
Особливо у багатьох виникає питання — а як бути, якщо є масив елементів, для кожного з них потрібно викликати асинхронну функцію і зробити щось важливе, коли завершиться остання. Очевидно, що звичайний for тут уже не допоможе:
Деякі хоробрості використовують рекурсію: для першого елемента викликати doSomething, в коллбеку рекурсивно викликати doSomething для наступного елемента, і видалити його з масиву. Так поки масив не виявиться порожнім. такі Приблизно так само працюють і Promises. Вони дозволяють записувати асинхронні функції у зручному послідовному вигляді. Код виглядає приблизно так:
Як це працює?
Очевидно, що кожен виклик then() додає функцію-аргумент у чергу запланованих функцій, проте поки що не виконує їх. А коли їх виконувати?
- черга відкладених функцій
- об'єкт з методом then() для додавання нових функцій у чергу
- рекурсивна функція, яка виконує першу відкладену функцію з черги та чекає на її завершення
- setTimeout(fn, 0) для запуску рекурсивної функції
Як дізнатися, коли саме завершуються функції? Найпростіше робити це явно – коли функція готова завершитись – нехай викличе спеціальну функцію next(). Звучить важко тому що часто зустрічається слово «функція»? Зараз,дивимося на код:
Тут все як описано вище - черга, рекурсивна функція, setTimeout та об'єкт із методом then().
У прикладі на екран виводиться "1", потім через секунду - "2" і "3", ще через секунду - "4" і "5".
Код можна стиснути практично до розміру твіту (137 байт) - https://gist.github.com/zserge/7021626 Можливо навіть додам його в 140byt.es.
А далі можна зробити так, щоб next() приймала аргументи, наприклад, результат роботи функції та об'єкт-помилка. А можна переглянути існуючі аналоги Promises/Futures. Головне, що тепер зрозуміло, що у них там усередині.