ÐбÑÑнÑе ÑÑнкÑии возвÑаÑаÑÑ ÑолÑко одно-единÑÑвенное знаÑение (или ниÑего).
ÐенеÑаÑоÑÑ Ð¼Ð¾Ð³ÑÑ Ð¿Ð¾ÑождаÑÑ (yield) множеÑÑво знаÑений одно за дÑÑгим, по меÑе Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ÑÑи. ÐенеÑаÑоÑÑ Ð¾ÑлиÑно ÑабоÑаÑÑ Ñ Ð¿ÐµÑебиÑаемÑми обÑекÑами и позволÑÑÑ Ð»ÐµÐ³ÐºÐ¾ ÑоздаваÑÑ Ð¿Ð¾Ñоки даннÑÑ .
ФÑнкÑиÑ-генеÑаÑоÑ
ÐÐ»Ñ Ð¾Ð±ÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð³ÐµÐ½ÐµÑаÑоÑа иÑполÑзÑеÑÑÑ ÑпеÑиалÑÐ½Ð°Ñ ÑинÑакÑиÑеÑÐºÐ°Ñ ÐºÐ¾Ð½ÑÑÑÑкÑиÑ: function*, коÑоÑÐ°Ñ Ð½Ð°Ð·ÑваеÑÑÑ Â«ÑÑнкÑиÑ-генеÑаÑоÑ».
ÐÑглÑÐ´Ð¸Ñ Ð¾Ð½Ð° Ñак:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
ФÑнкÑии-генеÑаÑоÑÑ Ð²ÐµÐ´ÑÑ ÑÐµÐ±Ñ Ð½Ðµ Ñак, как обÑÑнÑе. Ðогда ÑÐ°ÐºÐ°Ñ ÑÑнкÑÐ¸Ñ Ð²Ñзвана, она не вÑполнÑÐµÑ Ñвой код. ÐмеÑÑо ÑÑого она возвÑаÑÐ°ÐµÑ ÑпеÑиалÑнÑй обÑекÑ, Ñак назÑваемÑй «генеÑаÑоÑ», Ð´Ð»Ñ ÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ ÐµÑ Ð²Ñполнением.
ÐоÑ, поÑмоÑÑиÑе:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
// "ÑÑнкÑиÑ-генеÑаÑоÑ" ÑоздаÑÑ Ð¾Ð±ÑÐµÐºÑ "генеÑаÑоÑ"
let generator = generateSequence();
alert(generator); // [object Generator]
ÐÑполнение кода ÑÑнкÑии еÑÑ Ð½Ðµ наÑалоÑÑ:
ÐÑновнÑм меÑодом генеÑаÑоÑа ÑвлÑеÑÑÑ next(). ÐÑи вÑзове он запÑÑÐºÐ°ÐµÑ Ð²Ñполнение кода до ближайÑей инÑÑÑÑкÑии yield <знаÑение> (знаÑение Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑÑÑÑÑвоваÑÑ, в ÑÑом ÑлÑÑае оно пÑедполагаеÑÑÑ ÑавнÑм undefined). Ðо доÑÑижении yield вÑполнение ÑÑнкÑии пÑиоÑÑанавливаеÑÑÑ, а ÑооÑвеÑÑÑвÑÑÑее знаÑение â возвÑаÑаеÑÑÑ Ð²Ð¾ внеÑний код:
РезÑлÑÑаÑом меÑода next() вÑегда ÑвлÑеÑÑÑ Ð¾Ð±ÑÐµÐºÑ Ñ Ð´Ð²ÑÐ¼Ñ ÑвойÑÑвами:
value: знаÑение изyield.done:true, еÑли вÑполнение ÑÑнкÑии завеÑÑено, инаÑеfalse.
ÐапÑимеÑ, здеÑÑ Ð¼Ñ ÑоздаÑм генеÑаÑÐ¾Ñ Ð¸ полÑÑаем пеÑвое из возвÑаÑаемÑÑ Ð¸Ð¼ знаÑений:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
let one = generator.next();
alert(JSON.stringify(one)); // {value: 1, done: false}
Ðа даннÑй Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¼Ñ Ð¿Ð¾Ð»ÑÑили ÑолÑко пеÑвое знаÑение, вÑполнение ÑÑнкÑии оÑÑановлено на вÑоÑой ÑÑÑоке:
ÐовÑоÑнÑй вÑзов generator.next() Ð²Ð¾Ð·Ð¾Ð±Ð½Ð¾Ð²Ð¸Ñ Ð²Ñполнение кода и веÑнÑÑ ÑезÑлÑÑÐ°Ñ ÑледÑÑÑего yield:
let two = generator.next();
alert(JSON.stringify(two)); // {value: 2, done: false}
Ð, наконеÑ, поÑледний вÑзов завеÑÑÐ¸Ñ Ð²Ñполнение ÑÑнкÑии и веÑнÑÑ ÑезÑлÑÑÐ°Ñ return:
let three = generator.next();
alert(JSON.stringify(three)); // {value: 3, done: true}
СейÑÐ°Ñ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ Ð¿Ð¾Ð»Ð½Ð¾ÑÑÑÑ Ð²Ñполнен. ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ ÑвидеÑÑ ÑÑо по ÑвойÑÑÐ²Ñ done:true и обÑабоÑаÑÑ value:3 как оконÑаÑелÑнÑй ÑезÑлÑÑаÑ.
ÐовÑе вÑÐ·Ð¾Ð²Ñ generator.next() болÑÑе не имеÑÑ ÑмÑÑла. ÐпÑоÑем, еÑли они и бÑдÑÑ, Ñо не вÑзовÑÑ Ð¾Ñибки, но бÑдÑÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ Ð¾Ð´Ð¸Ð½ и ÑÐ¾Ñ Ð¶Ðµ обÑекÑ: {done: true}.
function* f(â¦) или function *f(â¦)?ÐÐµÑ ÑазниÑÑ, оба ÑинÑакÑиÑа коÑÑекÑнÑ.
Ðо обÑÑно пÑедпоÑÑиÑелен пеÑвÑй ваÑианÑ, Ñак как звÑздоÑка оÑноÑиÑÑÑ Ðº ÑÐ¸Ð¿Ñ Ð¾Ð±ÑÑвлÑемой ÑÑÑноÑÑи (function* â «ÑÑнкÑиÑ-генеÑаÑоÑ»), а не к ÐµÑ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ, Ñак ÑÑо Ñезонно ÑаÑположиÑÑ ÐµÑ Ñ Ñлова function.
ÐеÑÐµÐ±Ð¾Ñ Ð³ÐµÐ½ÐµÑаÑоÑов
Ðак вÑ, навеÑное, Ñже догадалиÑÑ Ð¿Ð¾ налиÑÐ¸Ñ Ð¼ÐµÑода next(), генеÑаÑоÑÑ ÑвлÑÑÑÑÑ Ð¿ÐµÑебиÑаемÑми обÑекÑами.
ÐозвÑаÑаемÑе ими знаÑÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ пеÑебиÑаÑÑ ÑеÑез for..of:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, заÑем 2
}
ÐÑглÑÐ´Ð¸Ñ Ð³Ð¾Ñаздо кÑаÑивее, Ñем иÑполÑзование .next().value, веÑно?
â¦Ðо обÑаÑиÑе внимание: пÑÐ¸Ð¼ÐµÑ Ð²ÑÑе вÑÐ²Ð¾Ð´Ð¸Ñ Ð·Ð½Ð°Ñение 1, заÑем 2. ÐнаÑение 3 вÑведено не бÑдеÑ!
ÐÑо из-за Ñого, ÑÑо пеÑÐµÐ±Ð¾Ñ ÑеÑез for..of игноÑиÑÑÐµÑ Ð¿Ð¾Ñледнее знаÑение, пÑи коÑоÑом done: true. ÐоÑÑомÑ, еÑли Ð¼Ñ Ñ
оÑим, ÑÑÐ¾Ð±Ñ Ð±Ñли вÑе знаÑÐµÐ½Ð¸Ñ Ð¿Ñи пеÑебоÑе ÑеÑез for..of, Ñо надо возвÑаÑаÑÑ Ð¸Ñ
ÑеÑез yield:
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, заÑем 2, заÑем 3
}
Так как генеÑаÑоÑÑ ÑвлÑÑÑÑÑ Ð¿ÐµÑебиÑаемÑми обÑекÑами, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ Ð²ÑÑ ÑвÑзаннÑÑ Ñ Ð½Ð¸Ð¼Ð¸ ÑÑнкÑионалÑноÑÑÑ, напÑÐ¸Ð¼ÐµÑ Ð¾Ð¿ÐµÑаÑÐ¾Ñ ÑаÑÑиÑÐµÐ½Ð¸Ñ ...:
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}
let sequence = [0, ...generateSequence()];
alert(sequence); // 0, 1, 2, 3
Ркоде вÑÑе ...generateSequence() пÑевÑаÑÐ°ÐµÑ Ð¿ÐµÑебиÑаемÑй обÑекÑ-генеÑаÑÐ¾Ñ Ð² маÑÑив ÑлеменÑов (подÑобнее ознакомиÑÑÑÑ Ñ Ð¾Ð¿ÐµÑаÑоÑом ÑаÑÑиÑÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ в главе ÐÑÑаÑоÑнÑе паÑамеÑÑÑ Ð¸ опеÑаÑÐ¾Ñ ÑаÑÑиÑениÑ)
ÐÑполÑзование генеÑаÑоÑов Ð´Ð»Ñ Ð¿ÐµÑебиÑаемÑÑ Ð¾Ð±ÑекÑов
ÐекоÑоÑое вÑÐµÐ¼Ñ Ð½Ð°Ð·Ð°Ð´, в главе ÐеÑебиÑаемÑе обÑекÑÑ, Ð¼Ñ Ñоздали пеÑебиÑаемÑй обÑÐµÐºÑ range, коÑоÑÑй возвÑаÑÐ°ÐµÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ from..to.
ÐавайÑе вÑпомним код:
let range = {
from: 1,
to: 5,
// for..of range вÑзÑÐ²Ð°ÐµÑ ÑÑÐ¾Ñ Ð¼ÐµÑод один Ñаз в Ñамом наÑале
[Symbol.iterator]() {
// ...он возвÑаÑÐ°ÐµÑ Ð¿ÐµÑебиÑаемÑй обÑекÑ:
// далее for..of ÑабоÑÐ°ÐµÑ ÑолÑко Ñ ÑÑим обÑекÑом, запÑаÑÐ¸Ð²Ð°Ñ ÑледÑÑÑие знаÑениÑ
return {
current: this.from,
last: this.to,
// next() вÑзÑваеÑÑÑ Ð¿Ñи каждой иÑеÑаÑии Ñикла for..of
next() {
// нÑжно веÑнÑÑÑ Ð·Ð½Ð°Ñение как обÑÐµÐºÑ {done:.., value :...}
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
}
};
// пÑи пеÑебоÑе обÑекÑа range бÑдÑÑ Ð²ÑÐ²ÐµÐ´ÐµÐ½Ñ ÑиÑла Ð¾Ñ range.from до range.to
alert([...range]); // 1,2,3,4,5
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ ÑÑнкÑиÑ-генеÑаÑÐ¾Ñ Ð´Ð»Ñ Ð¸ÑеÑаÑии, Ñказав ÐµÑ Ð² Symbol.iterator.
ÐÐ¾Ñ ÑÐ¾Ñ Ð¶Ðµ range, но Ñ Ð³Ð¾Ñаздо более компакÑнÑм иÑеÑаÑоÑом:
let range = {
from: 1,
to: 5,
*[Symbol.iterator]() { // кÑаÑÐºÐ°Ñ Ð·Ð°Ð¿Ð¸ÑÑ Ð´Ð»Ñ [Symbol.iterator]: function*()
for(let value = this.from; value <= this.to; value++) {
yield value;
}
}
};
alert( [...range] ); // 1,2,3,4,5
ÐÑо ÑабоÑаеÑ, поÑÐ¾Ð¼Ñ ÑÑо range[Symbol.iterator]() ÑепеÑÑ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð³ÐµÐ½ÐµÑаÑоÑ, и его меÑÐ¾Ð´Ñ â в ÑоÑноÑÑи Ñо, ÑÑо Ð¾Ð¶Ð¸Ð´Ð°ÐµÑ for..of:
- Ñ Ð½ÐµÐ³Ð¾ еÑÑÑ Ð¼ÐµÑод
.next() - коÑоÑÑй возвÑаÑÐ°ÐµÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð² виде
{value: ..., done: true/false}
ÐÑо не Ñовпадение, конеÑно. ÐенеÑаÑоÑÑ Ð±Ñли Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ Ð² ÑзÑк JavaScript, в ÑаÑÑноÑÑи, Ñ ÑелÑÑ ÑпÑоÑÑиÑÑ Ñоздание пеÑебиÑаемÑÑ Ð¾Ð±ÑекÑов.
ÐаÑÐ¸Ð°Ð½Ñ Ñ Ð³ÐµÐ½ÐµÑаÑоÑом намного коÑоÑе, Ñем иÑÑ
однÑй ваÑÐ¸Ð°Ð½Ñ Ð¿ÐµÑебиÑаемого range, и ÑоÑ
ÑанÑÐµÑ Ñе же ÑÑнкÑионалÑнÑе возможноÑÑи.
РпÑимеÑÐ°Ñ Ð²ÑÑе Ð¼Ñ Ð³ÐµÐ½ÐµÑиÑовали конеÑнÑе поÑледоваÑелÑноÑÑи, но Ð¼Ñ Ñакже можем ÑделаÑÑ Ð³ÐµÐ½ÐµÑаÑоÑ, коÑоÑÑй бÑÐ´ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð±ÐµÑконеÑно. ÐапÑимеÑ, беÑконеÑÐ½Ð°Ñ Ð¿Ð¾ÑледоваÑелÑноÑÑÑ Ð¿ÑевдоÑлÑÑайнÑÑ ÑиÑел.
ÐонеÑно, нам поÑÑебÑеÑÑÑ break (или return) в Ñикле for..of по ÑÐ°ÐºÐ¾Ð¼Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑ, инаÑе Ñикл бÑÐ´ÐµÑ Ð¿ÑодолжаÑÑÑÑ Ð±ÐµÑконеÑно, и ÑкÑÐ¸Ð¿Ñ Â«Ð·Ð°Ð²Ð¸ÑнеÑ».
ÐомпозиÑÐ¸Ñ Ð³ÐµÐ½ÐµÑаÑоÑов
ÐомпозиÑÐ¸Ñ Ð³ÐµÐ½ÐµÑаÑоÑов â ÑÑо оÑÐ¾Ð±ÐµÐ½Ð½Ð°Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ Ð³ÐµÐ½ÐµÑаÑоÑов, коÑоÑÐ°Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÐµÑ Ð¿ÑозÑаÑно «вÑÑÑаиваÑÑ» генеÑаÑоÑÑ Ð´ÑÑг в дÑÑга.
ÐапÑимеÑ, Ñ Ð½Ð°Ñ ÐµÑÑÑ ÑÑнкÑÐ¸Ñ Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑаÑии поÑледоваÑелÑноÑÑи ÑиÑел:
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}
ÐÑ Ñ Ð¾Ñели Ð±Ñ Ð¸ÑполÑзоваÑÑ ÐµÑ Ð¿Ñи генеÑаÑии более Ñложной поÑледоваÑелÑноÑÑи:
- ÑнаÑала ÑиÑÑÑ
0..9(Ñ ÐºÐ¾Ð´Ð°Ð¼Ð¸ Ñимволов 48â¦57) - за коÑоÑÑми ÑледÑÑÑ Ð±ÑÐºÐ²Ñ Ð² веÑÑ
нем ÑегиÑÑÑе
A..Z(ÐºÐ¾Ð´Ñ Ñимволов 65â¦90) - за коÑоÑÑми ÑледÑÑÑ Ð±ÑÐºÐ²Ñ Ð°Ð»ÑавиÑа
a..z(ÐºÐ¾Ð´Ñ Ñимволов 97â¦122)
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ ÑакÑÑ Ð¿Ð¾ÑледоваÑелÑноÑÑÑ Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑаÑии паÑолей, вÑбиÑаÑÑ ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ Ð¸Ð· Ð½ÐµÑ (Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ, еÑÑ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ Ð¿ÑнкÑÑаÑии), но ÑнаÑала ÐµÑ Ð½Ñжно ÑгенеÑиÑоваÑÑ.
РобÑÑной ÑÑнкÑии, ÑÑÐ¾Ð±Ñ Ð¾Ð±ÑединиÑÑ ÑезÑлÑÑаÑÑ Ð¸Ð· неÑколÑÐºÐ¸Ñ Ð´ÑÑÐ³Ð¸Ñ ÑÑнкÑий, Ð¼Ñ Ð²ÑзÑваем Ð¸Ñ , ÑÐ¾Ñ ÑанÑем пÑомежÑÑоÑнÑе ÑезÑлÑÑаÑÑ, а заÑем в конÑе Ð¸Ñ Ð¾Ð±ÑединÑем.
ÐÐ»Ñ Ð³ÐµÐ½ÐµÑаÑоÑов еÑÑÑ Ð¾ÑобÑй ÑинÑакÑÐ¸Ñ yield*, коÑоÑÑй позволÑÐµÑ Â«Ð²ÐºÐ»Ð°Ð´ÑваÑÑ» генеÑаÑоÑÑ Ð¾Ð´Ð¸Ð½ в дÑÑгой (оÑÑÑеÑÑвлÑÑÑ Ð¸Ñ
композиÑиÑ).
ÐÐ¾Ñ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð·Ð¸Ñией:
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}
function* generatePasswordCodes() {
// 0..9
yield* generateSequence(48, 57);
// A..Z
yield* generateSequence(65, 90);
// a..z
yield* generateSequence(97, 122);
}
let str = '';
for(let code of generatePasswordCodes()) {
str += String.fromCharCode(code);
}
alert(str); // 0..9A..Za..z
ÐиÑекÑива yield* делегиÑÑÐµÑ Ð²Ñполнение дÑÑÐ³Ð¾Ð¼Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑ. ÐÑÐ¾Ñ ÑеÑмин ознаÑаеÑ, ÑÑо yield* gen пеÑебиÑÐ°ÐµÑ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ gen и пÑозÑаÑно напÑавлÑÐµÑ ÐµÐ³Ð¾ вÑвод наÑÑжÑ. Ðак еÑли Ð±Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð±Ñли ÑгенеÑиÑÐ¾Ð²Ð°Ð½Ñ Ð²Ð½ÐµÑним генеÑаÑоÑом.
РезÑлÑÑÐ°Ñ â Ñакой же, как еÑли Ð±Ñ Ð¼Ñ Ð²ÑÑÑоили код из вложеннÑÑ Ð³ÐµÐ½ÐµÑаÑоÑов:
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}
function* generateAlphaNum() {
// yield* generateSequence(48, 57);
for (let i = 48; i <= 57; i++) yield i;
// yield* generateSequence(65, 90);
for (let i = 65; i <= 90; i++) yield i;
// yield* generateSequence(97, 122);
for (let i = 97; i <= 122; i++) yield i;
}
let str = '';
for(let code of generateAlphaNum()) {
str += String.fromCharCode(code);
}
alert(str); // 0..9a..zA..Z
ÐомпозиÑÐ¸Ñ Ð³ÐµÐ½ÐµÑаÑоÑов â еÑÑеÑÑвеннÑй ÑпоÑоб вÑÑавлÑÑÑ Ð²Ñвод одного генеÑаÑоÑа в поÑок дÑÑгого. Ðна не иÑполÑзÑÐµÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑÑ Ð¿Ð°Ð¼ÑÑÑ Ð´Ð»Ñ Ñ ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð¿ÑомежÑÑоÑнÑÑ ÑезÑлÑÑаÑов.
yield â доÑога в обе ÑÑоÑонÑ
Ðо ÑÑого моменÑа генеÑаÑоÑÑ ÑилÑно напоминали пеÑебиÑаемÑе обÑекÑÑ, Ñо ÑпеÑиалÑнÑм ÑинÑакÑиÑом Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑаÑии знаÑений. Ðо на Ñамом деле они намного моÑнее и гибÑе.
ÐÑÑ Ð´ÐµÐ»Ð¾ в Ñом, ÑÑо yield â доÑога в обе ÑÑоÑонÑ: он не ÑолÑко возвÑаÑÐ°ÐµÑ ÑезÑлÑÑÐ°Ñ Ð½Ð°ÑÑжÑ, но и Ð¼Ð¾Ð¶ÐµÑ Ð¿ÐµÑедаваÑÑ Ð·Ð½Ð°Ñение извне в генеÑаÑоÑ.
ЧÑÐ¾Ð±Ñ ÑÑо ÑделаÑÑ, нам нÑжно вÑзваÑÑ generator.next(arg) Ñ Ð°ÑгÑменÑом. ÐÑÐ¾Ñ Ð°ÑгÑÐ¼ÐµÐ½Ñ ÑÑановиÑÑÑ ÑезÑлÑÑаÑом yield.
ÐÑодемонÑÑÑиÑÑем ÑÑо на пÑимеÑе:
function* gen() {
// ÐеÑедаÑм вопÑÐ¾Ñ Ð²Ð¾ внеÑний код и ожидаем оÑвеÑа
let result = yield "2 + 2 = ?"; // (*)
alert(result);
}
let generator = gen();
let question = generator.next().value; // <-- yield возвÑаÑÐ°ÐµÑ Ð·Ð½Ð°Ñение
generator.next(4); // --> пеÑедаÑм ÑезÑлÑÑÐ°Ñ Ð² генеÑаÑоÑ
- ÐеÑвÑй вÑзов
generator.next()â вÑегда без аÑгÑменÑа, он наÑÐ¸Ð½Ð°ÐµÑ Ð²Ñполнение и возвÑаÑÐ°ÐµÑ ÑезÑлÑÑÐ°Ñ Ð¿ÐµÑвогоyield "2+2=?". Ðа ÑÑой ÑоÑке генеÑаÑÐ¾Ñ Ð¿ÑиоÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð²Ñполнение. - ÐаÑем, как показано на каÑÑинке вÑÑе, ÑезÑлÑÑаÑ
yieldпеÑÐµÑ Ð¾Ð´Ð¸Ñ Ð²Ð¾ внеÑний код в пеÑеменнÑÑquestion. - ÐÑи
generator.next(4)вÑполнение генеÑаÑоÑа возобновлÑеÑÑÑ, а4вÑÑ Ð¾Ð´Ð¸Ñ Ð¸Ð· пÑиÑÐ²Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ ÐºÐ°Ðº ÑезÑлÑÑаÑ:let result = 4.
ÐбÑаÑиÑе внимание, ÑÑо внеÑний код не обÑзан немедленно вÑзÑваÑÑ next(4). ÐÐ¼Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑÑебоваÑÑÑÑ Ð²ÑемÑ. ÐÑо не пÑоблема, генеÑаÑÐ¾Ñ Ð¿Ð¾Ð´Ð¾Ð¶Ð´ÑÑ.
ÐапÑимеÑ:
// возобновиÑÑ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ ÑеÑез некоÑоÑое вÑемÑ
setTimeout(() => generator.next(4), 1000);
Ðак видно, в оÑлиÑие Ð¾Ñ Ð¾Ð±ÑÑнÑÑ
ÑÑнкÑий, генеÑаÑÐ¾Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¾Ð±Ð¼ÐµÐ½Ð¸Ð²Ð°ÑÑÑÑ ÑезÑлÑÑаÑами Ñ Ð²ÑзÑваÑÑим кодом, пеÑÐµÐ´Ð°Ð²Ð°Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð² next/yield.
ЧÑÐ¾Ð±Ñ ÑделаÑÑ Ð¿ÑоиÑÑ Ð¾Ð´ÑÑее более оÑевиднÑм, Ð²Ð¾Ñ ÐµÑÑ Ð¾Ð´Ð¸Ð½ пÑÐ¸Ð¼ÐµÑ Ñ Ð±Ð¾Ð»ÑÑим колиÑеÑÑвом вÑзовов:
function* gen() {
let ask1 = yield "2 + 2 = ?";
alert(ask1); // 4
let ask2 = yield "3 * 3 = ?"
alert(ask2); // 9
}
let generator = gen();
alert( generator.next().value ); // "2 + 2 = ?"
alert( generator.next(4).value ); // "3 * 3 = ?"
alert( generator.next(9).done ); // true
ÐаÑÑинка вÑполнениÑ:
- ÐеÑвÑй
.next()наÑÐ¸Ð½Ð°ÐµÑ Ð²Ñполнение⦠Ðно Ð´Ð¾Ñ Ð¾Ð´Ð¸Ñ Ð´Ð¾ пеÑвогоyield. - РезÑлÑÑÐ°Ñ Ð²Ð¾Ð·Ð²ÑаÑаеÑÑÑ Ð²Ð¾ внеÑний код.
- ÐÑоÑой
.next(4)пеÑедаÑÑ4обÑаÑно в генеÑаÑÐ¾Ñ ÐºÐ°Ðº ÑезÑлÑÑÐ°Ñ Ð¿ÐµÑвогоyieldи возобновлÑÐµÑ Ð²Ñполнение. - â¦Ðно доÑ
Ð¾Ð´Ð¸Ñ Ð´Ð¾ вÑоÑого
yield, коÑоÑÑй ÑÑÐ°Ð½ÐµÑ ÑезÑлÑÑаÑом.next(4). - ТÑеÑий
next(9)пеÑедаÑÑ9в генеÑаÑÐ¾Ñ ÐºÐ°Ðº ÑезÑлÑÑÐ°Ñ Ð²ÑоÑогоyieldи возобновлÑÐµÑ Ð²Ñполнение, коÑоÑое завеÑÑаеÑÑÑ Ð¾ÐºÐ¾Ð½Ñанием ÑÑнкÑии, Ñак ÑÑоdone: true.
ÐолÑÑаеÑÑÑ Ñакой «пинг-понг»: каждÑй next(value) пеÑедаÑÑ Ð² генеÑаÑÐ¾Ñ Ð·Ð½Ð°Ñение, коÑоÑое ÑÑановиÑÑÑ ÑезÑлÑÑаÑом ÑекÑÑего yield, возобновлÑÐµÑ Ð²Ñполнение и полÑÑÐ°ÐµÑ Ð²ÑÑажение из ÑледÑÑÑего yield.
generator.throw
Ðак Ð¼Ñ Ð²Ð¸Ð´ÐµÐ»Ð¸ в пÑимеÑаÑ
вÑÑе, внеÑний код Ð¼Ð¾Ð¶ÐµÑ Ð¿ÐµÑедаваÑÑ Ð·Ð½Ð°Ñение в генеÑаÑÐ¾Ñ ÐºÐ°Ðº ÑезÑлÑÑÐ°Ñ yield.
â¦Ðо можно пеÑедаÑÑ Ð½Ðµ ÑолÑко ÑезÑлÑÑаÑ, но и иниÑииÑоваÑÑ Ð¾ÑибкÑ. ÐÑо еÑÑеÑÑвенно, Ñак как оÑибка ÑвлÑеÑÑÑ Ñвоего Ñода ÑезÑлÑÑаÑом.
ÐÐ»Ñ Ñого, ÑÑÐ¾Ð±Ñ Ð¿ÐµÑедаÑÑ Ð¾ÑÐ¸Ð±ÐºÑ Ð² yield, нам нÑжно вÑзваÑÑ generator.throw(err). Ð Ñаком ÑлÑÑае иÑклÑÑение err Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½ÐµÑ Ð½Ð° ÑÑÑоке Ñ yield.
ÐапÑимеÑ, здеÑÑ yield "2 + 2 = ?" пÑиведÑÑ Ðº оÑибке:
function* gen() {
try {
let result = yield "2 + 2 = ?"; // (1)
alert("ÐÑполнение пÑогÑÐ°Ð¼Ð¼Ñ Ð½Ðµ дойдÑÑ Ð´Ð¾ ÑÑой ÑÑÑоки, поÑÐ¾Ð¼Ñ ÑÑо вÑÑе Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½ÐµÑ Ð¸ÑклÑÑение");
} catch(e) {
alert(e); // Ð¿Ð¾ÐºÐ°Ð¶ÐµÑ Ð¾ÑибкÑ
}
}
let generator = gen();
let question = generator.next().value;
generator.throw(new Error("ÐÑÐ²ÐµÑ Ð½Ðµ найден в моей базе даннÑÑ
")); // (2)
ÐÑибка, коÑоÑÐ°Ñ Ð¿ÑобÑоÑена в генеÑаÑÐ¾Ñ Ð½Ð° ÑÑÑоке (2), пÑÐ¸Ð²Ð¾Ð´Ð¸Ñ Ðº иÑклÑÑÐµÐ½Ð¸Ñ Ð½Ð° ÑÑÑоке (1) Ñ yield. РпÑимеÑе вÑÑе try..catch пеÑеÑ
ваÑÑÐ²Ð°ÐµÑ ÐµÑ Ð¸ оÑобÑажаеÑ.
ÐÑли Ð¼Ñ Ð½Ðµ Ñ Ð¾Ñим пеÑÐµÑ Ð²Ð°ÑÑваÑÑ ÐµÑ, Ñо она, как и лÑбое обÑÑное иÑклÑÑение, «вÑвалиÑÑÑ» из генеÑаÑоÑа во внеÑний код.
ТекÑÑÐ°Ñ ÑÑÑока вÑзÑваÑÑего кода â ÑÑо ÑÑÑока Ñ generator.throw, оÑмеÑена (2). Таким обÑазом, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ оÑловиÑÑ ÐµÑ Ð²Ð¾ внеÑнем коде, как здеÑÑ:
function* generate() {
let result = yield "2 + 2 = ?"; // ÐÑибка в ÑÑой ÑÑÑоке
}
let generator = generate();
let question = generator.next().value;
try {
generator.throw(new Error("ÐÑÐ²ÐµÑ Ð½Ðµ найден в моей базе даннÑÑ
"));
} catch(e) {
alert(e); // Ð¿Ð¾ÐºÐ°Ð¶ÐµÑ Ð¾ÑибкÑ
}
ÐÑли же оÑибка и Ñам не пеÑÐµÑ Ð²Ð°Ñена, Ñо далÑÑе â как обÑÑно, она вÑÐ¿Ð°Ð´Ð°ÐµÑ Ð½Ð°ÑÑÐ¶Ñ Ð¸, еÑли не пеÑÐµÑ Ð²Ð°Ñена, «повалиÑ» ÑкÑипÑ.
ÐÑого
- ÐенеÑаÑоÑÑ ÑоздаÑÑÑÑ Ð¿Ñи помоÑи ÑÑнкÑий-генеÑаÑоÑов
function* f(â¦) {â¦}. - ÐнÑÑÑи генеÑаÑоÑов и ÑолÑко внÑÑÑи ниÑ
ÑÑÑеÑÑвÑÐµÑ Ð¾Ð¿ÐµÑаÑоÑ
yield. - ÐнеÑний код и генеÑаÑÐ¾Ñ Ð¾Ð±Ð¼ÐµÐ½Ð¸Ð²Ð°ÑÑÑÑ Ð¿ÑомежÑÑоÑнÑми ÑезÑлÑÑаÑами поÑÑедÑÑвом вÑзовов
next/yield.
Ð ÑовÑеменном JavaScript генеÑаÑоÑÑ Ð¸ÑполÑзÑÑÑÑÑ Ñедко. Ðо иногда они оказÑваÑÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñми, поÑÐ¾Ð¼Ñ ÑÑо ÑпоÑобноÑÑÑ ÑÑнкÑии обмениваÑÑÑÑ Ð´Ð°Ð½Ð½Ñми Ñ Ð²ÑзÑваÑÑим кодом во вÑÐµÐ¼Ñ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑовеÑÑенно ÑникалÑна. Ð, конеÑно, Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿ÐµÑебиÑаемÑÑ Ð¾Ð±ÑекÑов.
Также, в ÑледÑÑÑей главе Ð¼Ñ Ð±Ñдем изÑÑаÑÑ Ð°ÑинÑ
ÑоннÑе генеÑаÑоÑÑ, коÑоÑÑе иÑполÑзÑÑÑÑÑ, ÑÑÐ¾Ð±Ñ ÑиÑаÑÑ Ð¿Ð¾Ñоки аÑинÑ
Ñонно ÑгенеÑиÑованнÑÑ
даннÑÑ
(напÑимеÑ, поÑÑÑаниÑно загÑÑжаемÑе из ÑеÑи) в Ñикле for await ... of.
Рвеб-пÑогÑаммиÑовании Ð¼Ñ ÑаÑÑо ÑабоÑаем Ñ Ð¿Ð¾Ñоками даннÑÑ , Ñак ÑÑо ÑÑо еÑÑ Ð¾Ð´Ð¸Ð½ важнÑй ÑлÑÑай иÑполÑзованиÑ.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)