Page 245 - Браун Э. - Изучаем JavaScript. Руководство по созданию современных веб-сайтов - 2017
P. 245

function  ptimeout (delay)  {
           return  new  Promise ( f unction ( r e s olve ,  rej ect )  {
               setTimeout { r esolve ,  delay) ;
           } )   ;


          Следующее, что нам понадобится, - это пускатель генератора (generator runner).
       Не забывайте, что генераторы не являются по своей природе асинхронными. Но по­
       скольку они позволяют функциям общаться с вызывающей стороной,  мы можем
       создать функцию, которая будет управлять этой связью и  знать,  как обрабатывать
       асинхронные вызовы. Поэтому создадим функцию grun (generator run - пуск гене­
       ратора).

       function  grun ( g )    {
           const  i t   =  g  ( ) ;
            ( f unction  iterate (v l )
                              a
               const  х  =  it . n ext ( v al ) ;
               if ( !  .   don )    {
                   х
                       e
                                            i
                   i f ( x . v a l ue  instanceof  Prom s e )    {
                      x . v a l ue . t hen ( iterate )  . c atch ( e rr  =>  i t . throw ( e r ) )  ;
                                                                   r
                     else  {
                       setTimeout ( i terate ,  О ,   x  . v alu ) ;
                                                  e
            } )   ( ) ;


                  Данная функция grun основана на функции runGenerator, представ­
                  ленной Кайлом Симпсоном (Kyle Simpson) в его превосходной серии
                  статей о генераторах.  Я  настоятельно  рекомендую  прочитать эти
                  статьи как дополнение к данному тексту.

          Это очень скромный рекурсивный пускатель генератора. Вы передаете ему функ­
       цию генератора, и он запускает его. Как уже было сказано в главе 6, генераторы, кото­
       рые вызывают оператор yield, будут делать паузу, пока не будет вызван метод next
       его итератора.  Данная  функция делает это рекурсивно. Если итератор  возвращает
       обязательство, она ожидает выполнения обязательства перед возобновлением итера­
       тора. С другой стороны, если итератор возвращает простое значение, она немедлен­
       но возобновляет итерацию. Вы можете задаться вопросом "Почему происходит вызов
       setTirneout  вместо обычного непосредственного вызова  i terate?" Причина в том,
       что мы получим более эффективный код при отказе от синхронной рекурсии (асин­
       хронная рекурсия позволяет движку JavaScript освобождать ресурсы куда быстрее).
          Вы можете подумать "Как много суеты!" и "Это называется упрощает жизнь?" Од­
       нако сложная часть завершена. Функция nfcall позволяет увязать прошлое (функции



       248      Глава 1 4 . Асинхронное программирование
   240   241   242   243   244   245   246   247   248   249   250