Почему `setTimeout` не работает, когда обратный вызов передается через yield? - PullRequest
0 голосов
/ 17 октября 2018

В следующем коде:

function so() {
  console.log('inside the timer')
}

function* sogen() {
  const callback = yield;

  setTimeout(callback, 2000);

  return 1;
}

function() {
  var gen = sogen();
  gen.next(so), gen.next(so);
}()

Почему я никогда не достигаю функции so?

Ответы [ 4 ]

0 голосов
/ 12 ноября 2018

Здесь вы используете функцию генератора в качестве наблюдателя.

при создании объекта генератора он фактически не вызывается.

при первом вызове gen.next (так) в первый раз, он действует как вызывающий вызов для генератора, а передаваемое ему значение игнорируется. (первый вызов переводит выполнение к первому выходу.)

при втором вызове gen.затем (так) yield получает 'function so () {}', и остальная часть кода выполняется.

Пожалуйста, посмотрите на эту ссылку, чтобы иметь больше ясности: функция генератора в качестве наблюдателя

Ваш рабочий фрагмент

0 голосов
/ 10 ноября 2018

предоставленный вами отсканированный код теперь должен работать (за исключением синтаксической ошибки в IIFE).Я переписал это для ясности.

function so() {
  console.log('inside the timer')
}

function* sogen()
{
  const callback = yield; // line 1
  setTimeout(callback, 2000); // line 2
  return 1; // line 3
}

Теперь давайте посмотрим, как с помощью итератора, возвращенного из sogen, мы можем вызвать so.

var iter = sogen();

Мы создали итератор .Вызвав метод итератора next, мы можем ускорить выполнение генератора sogen.

iter.next();

После этого вызова состояние итератора теперь заморожено в строке 1 строки sogen.yield был обнаружен и {value: undefined, done: false} был возвращен из вызова .next().На данный момент мы готовы передать наш обратный вызов.

iter.next(so);

Мы передали обратный вызов в метод next, и выполнение возобновляется в строке 1. Переменная callback теперь имеет значение so функция.Продолжая в строке 2 - вызывается setTimeout.Через две секунды будет вызвана наша функция so.Но перед этим код продолжает строку 3. Вызов .next(so) возвращает {value: 1, done: true}.Теперь мы ждем.

Через две секунды вы увидите, что inside the timer было зарегистрировано на консоли.

0 голосов
/ 11 ноября 2018

tl; д-р вам нужно обернуть IIFE скобками или вообще не использовать IIFE.

Использование генераторов в порядке, и один разВы добавляете парены, все работает как обычно.

Обратите внимание, что вам не нужно IIFE для запуска кода, но мой ответ ниже объясняет, почему то, что у вас не работает.

Объявления функций и выражения функций

Основная проблема, с которой вы столкнулись, заключается в следующем коде:

function() {
  var gen = sogen();
  gen.next(so);
  gen.next(so);
}()

Это приведет к ошибке, аналогичной:

Uncaught SyntaxError: Неожиданный токен (

Проблема здесь в том, что вы пытаетесь использовать объявление функции в качестве выражения функции .

Из MDN (выделено мной):

Выражение функции очень похоже и имеет почти такой же синтаксис, что и оператор функции (подробности см. В операторе функции). Основное отличие междуВыражение функции и оператор функции является фуnction name, которое может быть опущено в выражениях функций для создания анонимных функций. Выражение функции может использоваться как IIFE (выражение вызова с немедленным вызовом), которое запускается, как только оно определено .См. Также главу о функциях для получения дополнительной информации.

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

Один из распространенных способов написания выражения функции - заключить функцию в скобки:

function a() { return 'a'; } // Function declaration
(function b() { return 'b'; }) // Function expression

Чтобы преобразовать это в IIFE, вы можете добавить вызов ()в конце:

(function c() { return 'c'; })() // IIFE

, который немедленно вызывает функцию.Обратите внимание, что я предпочитаю ставить скобки вызова внутри переносящих скобок, но это просто стилистический выбор и работает таким же образом:

(function c() { return 'c'; }()) // IIFE

Вот код из ответа плюс скобки, заключающие IIFE:

function so() {
  console.log('inside the timer');
}

function* sogen() {
  const callback = yield;

  setTimeout(callback, 2000);

  return 1;
}

(function() {
  const gen = sogen();
  gen.next(so);
  gen.next(so);
}())

Либо просто удалите IIFE:

const gen = sogen();
gen.next(so);
gen.next(so);

или, если вам нужно объявление функции, вызовите функцию в следующей строке:

function run() {
  const gen = sogen();
  gen.next(so);
  gen.next(so);
}
run();
0 голосов
/ 17 октября 2018

В вашем фрагменте sogen - это не обычная функция, это генератор, как указано *.

. Вы можете вызвать генератор, чтобы получить то, что по сути является итератором, который может бытьуправляется с помощью метода .next() и может приостанавливать его выполнение при каждом обнаружении ключевого слова yield.

var it = sogen();
it.next();

Присвоенное вам назначение (const callback = yield) будет разрешено последующим .next (), например:

it.next(function myCallback() { /* ... */ });

Генератор будет продолжать работать до следующего yield или до конца функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...