Yield – дорога в обе стороны
Он не только возвращает результат наружу, но и может передавать значение извне в генератор.
Вызов let result = yield value делает следующее:
ü Возвращает value во внешний код, приостанавливая выполнение генератора.
ü Внешний код может обработать значение, и затем вызвать next с аргументом: generator.next(arg).
ü Генератор продолжит выполнение, аргумент next будет возвращён как результат yield (и записан в result).
Продемонстрируем это на примере:
function* gen() {
// Передать вопрос во внешний код и подождать ответа
let result = yield "2 + 2?";
alert(result);
}
let generator = gen();
let question = generator.next().value; // "2 + 2?"
setTimeout(() => generator.next(4), 2000);
На рисунке ниже прямоугольником изображён генератор, а вокруг него – «внешний код», который с ним взаимодействует:
На этой иллюстрации показано то, что происходит в генераторе:
ü Первый вызов generator.next() – всегда без аргумента, он начинает выполнение и возвращает результат первого yield («2+2?»). На этой точке генератор приостанавливает выполнение.
ü Результат yield переходит во внешний код (в question). Внешний код может выполнять любые асинхронные задачи, генератор стоит «на паузе».
ü Когда асинхронные задачи готовы, внешний код вызывает generator.next(4) с аргументом. Выполнение генератора возобновляется, а 4 выходит из присваивания как результат let result = yield ....
Generator.throw
Как мы видели в примерах выше, внешний код может вернуть генератору в качестве результата yield любое значение. Но «вернуть» можно не только результат, но и ошибку!
Для того, чтобы передать в yield ошибку, используется вызов generator.throw(err). При этом на строке с yield возникает исключение. Например:
function* gen() {
try {
// в этой строке возникнет ошибка
let result = yield "Сколько будет 2 + 2?";
}
catch(e) {
alert(e); // выведет ошибку
}
}
let generator = gen();
let question = generator.next().value;
generator.throw(new Error("ответ не найден в моей базе данных"));
Асинхронный код
Одна из основных областей применения генераторов – написание асинхронного кода.
Общий принцип такой:
ü Генератор yield'ит не просто значения, а промисы.
ü Есть специальная «функция-чернорабочий» execute(generator) которая запускает генератор, последовательными вызовами next получает из него промисы – один за другим, и, когда очередной промис выполнится, возвращает его результат в генератор следующим next.
ü Последнее значение генератора (done:true) execute уже обрабатывает как окончательный результат – например, возвращает через промис куда-то ещё, во внешний.
function* doAsyncThings() {
const result1 = doAsyncThing();
const result2 = doAsyncThing(result1);
}
function execute(generator, yieldValue) {
let next = generator.next(yieldValue);
if (next.done) {
return next.value;
}
next.value.then(
result => execute(generator, result),
err => generator.throw(err)
);
}
29. Синтаксис диалекта регулярных выражений, доступный в ES2015. Метасимволы, группировки, обратные ссылки, квантификаторы, символьный класс и выбор, позиционные проверки.
Регулярные выражения (Regular Expressions, RegEx, RegExp) – отдельный язык (может быть использован в редакторах и других языках программирования), который позволяет описать некий текстовый шаблон.
Perl Compatible Regular Expressions (PCRE) - библиотека, реализующая работу регулярных выражений в стиле Perl (с некоторыми отличиями).
Регулярное выражение состоит из двух типов символов. Специальные символы (вроде * в файловых шаблонах) называются метасимволами. Все остальные символы, т. е. обычный текст, называются литералами.
Позиционная проверка (привязка идет к позиции, а не к символу)
^ - начало строки, $ - конец строки (^$ — пустая строка)
/cat/ = «cat» и «vocation»
/^cat/ = «cats», /cat$/ = «scat»
[] – символьный класс
В квадратных скобках происходит перечисление символов, которые могут встретиться (совпасть может только один символ). Позиционные метасимволы, как метасимволы, в символьном классе не работают.
/gr[ea]y/
/<[Hh][123456]>/ — заголовок HTML
Метасимвол символьного класса ‘-’ (дефис) обозначает интервал символов.
[0-9] [a-z] [а-яё]
/<[Hh][1-6]>/
Инвертированные символьные классы
Например, /[^1-6]/ совпадает с символом, не принадлежащим интервалу от 1 до 6. Префикс ^ в каком-то смысле «инвертирует» список, вместо того чтобы перечислять символы, принадлежащие классу, вы перечисляете символы, не входящие в него.
| - конструкция выбора
/gr(a|e)y/
Границы слов (\b, \<, \>)
/\bcat\b/
/\<cat\>/
Квантификаторы
жадный (по умолчанию) – захватывает все, что можно захватить, а потом отпускает
не жадный (квантификатор?) – захватывает по-минимуму
захватывающий (квантификатор+) – не отпускает то, что уже захватил
? - один или ноль совпадений
+ - один или несколько совпадений
* - ноль или несколько совпадений
{min,max} – от min до max совпадений
/colou?r/ (применится к символу ”u”, то есть он может встретиться 0 или один раз)
() - сохраняющая группировка (“\1” - обратная ссылка)
В программах с поддержкой обратных ссылок круглые скобки «запоминают» текст, совпавший с находящимся в них подвыражением, а специальный метасимвол «\1» представляет этот текст (каким бы он ни был на тот момент) в оставшейся части регулярного выражения.
/\b([A-Za-z]+)\s+(\1\s+)*\1\b/ - поиск повторяющихся слов
(?:) – несохраняющая группировка
(?>) - атомарная группировка (совпадение или включено полностью, или полностью исключено)
Метасимволы регулярных выражений:
. – [^\n\r]
\t - символ табуляции
\n - символ новой строки
\r - символ возврата каретки
\s – множество интервальных символов
\S – инвертированное множество интервальных символов
\w - [a-zA-Z0-9_]
\W - [^a-zA-Z0-9_]
\d - [0-9]
\D - [^0-9]
Ключи (флаги):
/i — игнорирование регистра
/g — глобальный поиск
/x — свободное форматирование (любой интервальный символ игнорируется)
/s — рассматривать все, как сплошную строку
/m — разбивает текст на логические строки
/y – начинать поиск с позиции предыдущего совпадения
PCRE:
(?P=name) – ссылка на именованное сохранение
(?P<name>..) – именованное сохранение
\A и \Z – начало и конец всего текста
\Q..\E – литеральный режим (метасимволы внутри игнорируются)
\pL – литеральный символ юникода
\pN – числовой символ юникода
\pZ – интервальный символ юникода
(?i:…) и (?-i:…) – применение или отключение ключа к фрагменту
Позиционная проверка
Опережающая: позитивная (?=…) и негативная (?!...) – позиция, после которой идет или не идет данная последовательность
Ретроспективная: позитивная (?<=…) и негативная (?<!...) – позиция, перед которой идет или не идет данная последовательность
Раскрутка цикла
начало норм* (спец норм*)* конец
Поиск текста в ограничителях:
"(\\.|[^\\"])*"
"[^\\"]*(\\.[^\\"]*)*"