yield*
Baseline Широко доступно
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с сентября 2016 года.
Оператор yield* может использоваться внутри генераторных (синхронных или асинхронных) функций для делегирования другому итерируемому объекту, такому как Generator. Внутри асинхронных генераторных функций он дополнительно может использоваться для делегирования другому асинхронному итерируемому объекту, такому как AsyncGenerator.
Попробуйте
function* func1() {
yield 42;
}
function* func2() {
yield* func1();
}
const iterator = func2();
console.log(iterator.next().value);
// Expected output: 42
Синтаксис
yield* expression
Параметры
-
expressionНеобязательно - Итерируемый объект.
Возвращаемое значение
Возвращает значение, возвращаемое этим итератором при его закрытии (когда done является true).
Описание
Выражение yield* итерирует по операнду и выдает каждое значение, возвращаемое им. Оно делегирует итерацию текущего генератора нижележащему итератору — который мы будем называть "генератором" и "итератором" соответственно. yield* сначала получает итератор из операнда, вызывая метод [Symbol.iterator]() последнего. Затем, каждый раз, когда вызывается метод next() генератора, yield* вызывает метод next() итератора, передавая аргумент, полученный методом next() генератора (всегда undefined для первого вызова), и выдавая тот же объект результата, что и возвращаемый методом next() итератора. Если результат итератора имеет done: true, то выполнение выражения yield* останавливается и возвращается value этого результата.
Оператор yield* также перенаправляет методы throw() и return() текущего генератора на нижележащий итератор. Если текущий генератор преждевременно закрывается через один из этих методов, нижележащий итератор будет уведомлен. Если вызывается метод throw()/return() генератора, то вызывается метод throw()/return() нижележащего итератора с тем же аргументом. Возвращаемое значение throw()/return() обрабатывается аналогично результату метода next(), и если метод выбрасывает исключение, то исключение распространяется из выражения yield*.
Если у нижележащего итератора нет метода return(), выражение yield* превращается в инструкцию return, так же, как при вызове return() на приостановленном выражении yield.
Если у нижележащего итератора нет метода throw(), это приводит к тому, что yield* выбрасывает TypeError – но перед выбрасыванием ошибки вызывается метод return() нижележащего итератора, если он существует.
Примеры
Делегирование другому генератору
В следующем коде значения, выдаваемые g1(), возвращаются из вызовов next() так же, как и те, которые выдаются g2().
function* g1() {
yield 2;
yield 3;
yield 4;
}
function* g2() {
yield 1;
yield* g1();
yield 5;
}
const gen = g2();
console.log(gen.next()); // {value: 1, done: false}
console.log(gen.next()); // {value: 2, done: false}
console.log(gen.next()); // {value: 3, done: false}
console.log(gen.next()); // {value: 4, done: false}
console.log(gen.next()); // {value: 5, done: false}
console.log(gen.next()); // {value: undefined, done: true}
Другие итерируемые объекты
Помимо объектов-генераторов, yield* также может yield другие виды итерируемых объектов (например, массивы, строки или объекты arguments).
function* g3(...args) {
yield* [1, 2];
yield* "34";
yield* args;
}
const gen = g3(5, 6);
console.log(gen.next()); // {value: 1, done: false}
console.log(gen.next()); // {value: 2, done: false}
console.log(gen.next()); // {value: "3", done: false}
console.log(gen.next()); // {value: "4", done: false}
console.log(gen.next()); // {value: 5, done: false}
console.log(gen.next()); // {value: 6, done: false}
console.log(gen.next()); // {value: undefined, done: true}
Значение самого выражения yield*
yield* является выражением, а не инструкцией, поэтому оно вычисляется в значение.
function* g4() {
yield* [1, 2, 3];
return "foo";
}
function* g5() {
const g4ReturnValue = yield* g4();
console.log(g4ReturnValue); // 'foo'
return g4ReturnValue;
}
const gen = g5();
console.log(gen.next()); // {value: 1, done: false}
console.log(gen.next()); // {value: 2, done: false}
console.log(gen.next()); // {value: 3, done: false} done is false because g5 generator isn't finished, only g4
console.log(gen.next()); // {value: 'foo', done: true}
Использование с асинхронными генераторами
async function* g1() {
await Promise.resolve(0);
yield "foo";
}
function* g2() {
yield "bar";
}
async function* g3() {
// Can use yield* on both async and sync iterators
yield* g1();
yield* g2();
}
const gen = g3();
console.log(await gen.next()); // {value: "foo", done: false}
console.log(await gen.next()); // {value: "bar", done: false}
console.log(await gen.next()); // {done: true}
Перенаправление методов
Методы next(), throw() и return() текущего генератора перенаправляются на нижележащий итератор.
const iterable = {
[Symbol.iterator]() {
let count = 0;
return {
next(v) {
console.log("next called with", v);
count++;
return { value: count, done: false };
},
return(v) {
console.log("return called with", v);
return { value: "iterable return value", done: true };
},
throw(v) {
console.log("throw called with", v);
return { value: "iterable thrown value", done: true };
},
};
},
};
function* gf() {
yield* iterable;
return "gf return value";
}
const gen = gf();
console.log(gen.next(10));
// next called with undefined; the argument of the first next() call is always ignored
// { value: 1, done: false }
console.log(gen.next(20));
// next called with 20
// { value: 2, done: false }
console.log(gen.return(30));
// return called with 30
// { value: 'iterable return value', done: true }
console.log(gen.next(40));
// { value: undefined, done: true }; gen is already closed
const gen2 = gf();
console.log(gen2.next(10));
// next called with undefined
// { value: 1, done: false }
console.log(gen2.throw(50));
// throw called with 50
// { value: 'gf return value', done: true }
console.log(gen.next(60));
// { value: undefined, done: true }; gen is already closed
Если метод return()/throw() нижележащего итератора возвращает done: false, текущий генератор продолжает выполнение, и yield* продолжает делегировать нижележащему итератору.
const iterable = {
[Symbol.iterator]() {
let count = 0;
return {
next(v) {
console.log("next called with", v);
count++;
return { value: count, done: false };
},
return(v) {
console.log("return called with", v);
return { value: "iterable return value", done: false };
},
};
},
};
function* gf() {
yield* iterable;
return "gf return value";
}
const gen = gf();
console.log(gen.next(10));
// next called with undefined
// { value: 1, done: false }
console.log(gen.return(20));
// return called with 20
// { value: 'iterable return value', done: false }
console.log(gen.next(30));
// { value: 2, done: false }; gen is not closed
Если у нижележащего итератора нет метода throw(), и вызывается метод throw() генератора, yield* выбрасывает ошибку.
const iterable = {
[Symbol.iterator]() {
let count = 0;
return {
next(v) {
count++;
return { value: count, done: false };
},
};
},
};
function* gf() {
yield* iterable;
return "gf return value";
}
const gen = gf();
gen.next(); // First next() starts the yield* expression
gen.throw(20); // TypeError: The iterator does not provide a 'throw' method.
Спецификации
| Спецификация |
|---|
| ECMAScript® 2027 Language Specification # sec-generator-function-definitions-runtime-semantics-evaluation |
Совместимость с браузерами
| Настольные компьютеры | Мобильные устройства | Сервер | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on iOS | Samsung Internet | WebView Android | WebView on iOS | Bun | Deno | Node.js | |
yield_star |
39 |
12 |
27Начиная с Firefox 33, разбор выраженияyield был обновлен в соответствии со спецификацией ES2015. |
26 |
10 |
39 |
27Начиная с Firefox for Android 33, разбор выраженияyield был обновлен в соответствии со спецификацией ES2015. |
26 |
10 |
4.0 |
39 |
10 |
1.0.0 |
1.0 |
4.0.0 |
См. также
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*