[Из песочницы] Моя любимая особенность генераторов

Уже ни раз на хабре писали о том, как работают новые генераторы и я даже не буду первым, кто напишет о их возможности приостанавливать своё выполнение инструкцией yield.После прочтения статьи «Генераторы в node.js (новый способ борьбы с лапшой)» меня не покидала мысль о том, что можно обойтись без лапши-callBack’ов, но я никак не мог смириться с тем, что для каждой асинхронной функции, которую мы хотим вызвать, нужно писать функцию-обёртку.

И тут родилась идея! Очень простая, а суть её в том, что внутри генератора имеется ссылка на функцию n, которую мы передаём асинхронным функциям как callBack, приостанавливаем генератор при помощи yield, а затем наша функция n продолжает выполнение генератора, передавая в него массив, сформированный из аргументов, с которыми она была вызвана.

Заинтересованных прошу под кат.

Как это выглядит на практике? А вот так: есть функция Sync, которая, собственно, и делает возможным подобные шаманства. Она создаёт функцию n, затем инициализирует генератор, передавая эту функцию в него и запускает всё это дело. Sync=function (fn) { var gen; var callBack=function () { gen.next (Array.prototype.slice.call (arguments,0)); }; gen=fn (callBack); gen.next (); }; А теперь самое интересное!

var fs=require ('fs'); //Подключаем модуль FS console.log (1); //Выводим на экран 1 Sync (function*(cb) { //Передаём в функцию Sync функцию-генератор с одним аргументом, принимающим callBack для асинхронных функций console.log (2); //Выводим на экран 2 yield fs.readFile ('sync.js','utf-8', cb); //Вызываем асинхронную функцию и передаём ей ранее принятый callBack, после чего прерываем работу функции console.log (4); //Выводим на экран 4 }); console.log (3); //Выводим на экран 3 На выводе мы увидим:1234

4 выводится после 3 потому, что при помощи конструкции yield мы прервали работу функции-генератора, а затем асинхронная функция readFile завершила выполнение и вызвала callBack, который мы ей передали, который в свою очередь и продолжил выполнения функции-генератора.

Так можно проследить, что после первой приостановки наш генератор сразу становится отдельным потоком, о чём очень важно помнить. Таким способом не получиться приостановить текущий поток только потому, что вам захотелось использовать асинхронные функции синхронно. Это лишь метод борьбы с лапшой, ничего больше.

А теперь самое вкусное: возврат результатов!

var fs=require ('fs'); Sync (function*(cb) { var result=yield fs.readFile ('sync.js','utf-8', cb); console.log (result[1]); }); Все помнят, что readFile передаёт в callBack 2 аргумента:

Сообщение об ошибке, если она случилась Данные из файла Именно по этому мы обратились ко второму элементу массива.

Просто и элегантно, на мой взгляд. Осталось дождаться, когда генераторы выйдут в стабильных сборках nodejs и браузерах.

© Habrahabr.ru