You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
عبارت `*yield` اجرا را به یک generator دیگر میسپارد(اصطلاحا `delegate` میکند). بدان معنا که `yeild* gen` روی `gen` ایتریت میکند و به صورت درونی مقدار yield شده را به بیرون هدایت میکند؛ انگار که کلا مقدار توسط generator دوم تولید شده است.
305
283
306
284
اگر از generatorها به صورت inline و تو در تو استفاده کنیم نیز به همان نتیجه میرسیم:
307
285
308
286
```js run
309
-
310
287
function*generateSequence(start, end) {
311
-
312
288
for (let i = start; i <= end; i++) yield i;
313
-
314
289
}
315
290
316
291
function*generateAlphaNum() {
317
292
318
293
\*!*
319
-
320
294
// yield* generateSequence(48, 57);
321
-
322
295
for (let i =48; i <=57; i++) yield i;
323
296
324
297
// yield* generateSequence(65, 90);
325
-
326
298
for (let i =65; i <=90; i++) yield i;
327
299
328
300
// yield* generateSequence(97, 122);
329
-
330
301
for (let i =97; i <=122; i++) yield i;
331
-
332
302
\*/!*
333
303
334
304
}
335
305
336
306
let str ='';
337
307
338
308
for(let code ofgenerateAlphaNum()) {
339
-
340
309
str +=String.fromCharCode(code);
341
-
342
310
}
343
311
344
312
alert(str); // 0..9A..Za..z
345
-
346
313
```
347
314
348
-
349
315
ترکیب generatorها یک راه معقول برای استفاده از جریان یک generator درون دیگری است و از حافظه بیشتر برای ذخیره مقادیر استفاده نمیکند.
350
316
351
317
## yield یک خیابان دو طرفه است.
@@ -359,67 +325,50 @@ alert(str); // 0..9A..Za..z
359
325
برای مثال:
360
326
361
327
```js run
362
-
363
328
function*gen() {
364
-
365
329
\*!*
366
-
367
330
// یک سوال را به کد بیرونی برگردانید و منتظر جواب شوید
368
-
369
331
let result =yield"2 + 2 = ?"; // (*)
370
-
371
332
\*/!*
372
333
373
334
alert(result);
374
-
375
335
}
376
336
377
337
let generator =gen();
378
338
379
339
let question =generator.next().value; // <-- مقدار را بر میگرداند yield
380
340
381
341
generator.next(4); // --> برمیگرداند generator نتیجه را به
382
-
383
342
```
384
343
385
-
386
344

387
345
388
346
1. نمیتوان اولین بار که `()generator.next` صدا میشود به آن argument داد و در صورت داده شدن، نادید گرفته خواهد شد. پس از صدا شدن متود، اجرای generator شروع میشود و مقدار اولین yield را برمیگرداند. اکنون اجرای generator متوقف شده و در خط `*` مانده است.
389
-
390
347
2. سپس مانند تصویر بالا، نتیجه yield اول در متغیر `question` ذخیره میشود.
391
-
392
348
3. با اجرای `generator.next(4)`، اجرای generator دوباره شروع میشود و مقدار متغیر `result` برابر `4` میشود.
393
349
394
350
توجه داشته باشید که نیاز نیست کد بیرونی فورا `(4)next` را صدا کند؛ اگر طول بکشد، generator صبر خواهد کرد.
395
351
396
352
برای مثال:
397
353
398
354
```js
399
-
400
355
// پس از تاخیری دوباره شروع میشود generator اجرای
401
-
402
356
setTimeout(() =>generator.next(4), 1000);
403
-
404
357
```
405
358
406
-
407
359
همانطور که مشاهده میشود بر خلاف توابع معمولی، یک generator و کد صدا زنندهاش میتوانند با هم مقادیر را از طریق `next/yield` رد و بدل کنند.
برای مثال اینجا yield شدن "2 + 2 = ?" باعث ارور میشود:
461
404
462
405
```js run
463
-
464
406
function*gen() {
465
-
466
407
try {
467
-
468
408
let result =yield"2 + 2 = ?"; // (1)
469
409
470
410
alert("اجرا به اینجا نمیرسد چون خط بالا ارور پرتاب کرده است");
471
-
472
411
} catch(e) {
473
-
474
412
alert(e); // ارور را نشان میدهد
475
-
476
413
}
477
-
478
414
}
479
415
480
416
let generator =gen();
481
417
482
418
let question =generator.next().value;
483
419
484
420
\*!*
485
-
486
421
generator.throw(newError("پاسخ در دیتابیس من نیست")); // (2)
487
-
488
422
\*/!*
489
-
490
423
```
491
424
492
-
493
425
ارور پرتاب شده به داخل generator در خط `2` باعث exception در خط `1` دارای yield میشود که در مثال بالا توسط `try..catch` گرفته شده و نمایش داده میشود.
494
426
495
427
اگر آن را catch نکنیم، مانند هر exception دیگری اجرا از generator به کد بیرونی منتقل میشود.
496
428
497
429
خط فعلی کد صدا زننده، خط دارای `generator.throw` با لیبل `2` است. پس خطا را این گونه هم میتوان گرفت:
498
430
499
431
```js run
500
-
501
432
function*generate() {
502
-
503
433
let result =yield"2 + 2 = ?"; // خطا در این خط
504
-
505
434
}
506
435
507
436
let generator =generate();
508
437
509
438
let question =generator.next().value;
510
439
511
440
\*!*
512
-
513
441
try {
514
-
515
442
generator.throw(newError("پاسخ در دیتابیس من نیست"));
516
-
517
443
} catch(e) {
518
-
519
444
alert(e); // ارور را نمایش میدهد
520
-
521
445
}
522
-
523
446
\*/!*
524
-
525
447
```
526
448
527
-
528
449
اگر ارور را catch نکنیم، در صورت وجود کد بیرونی اجرا به آن منتقل میشود و اگر آنجا نیز هندل نشده باشد، اجرای کد با خطا پایان میپذیرد.
529
450
530
451
## generator.return
531
452
532
453
این متود اجرای generator را به اتمام میرساند و مقدار argument را به عنوان نتیجه برمیگرداند.
533
454
534
455
```js
535
-
536
456
function*gen() {
537
-
538
457
yield1;
539
-
540
458
yield2;
541
-
542
459
yield3;
543
-
544
460
}
545
461
546
462
constg=gen();
547
463
548
464
g.next(); // { value: 1, done: false }
549
-
550
465
g.return("foo"); // { value: "foo", done: true }
551
-
552
466
g.next(); // { value: undefined, done: true }
553
-
554
467
```
555
468
556
-
557
469
اگر در یک generatorخاتمه یافته دوباره از `()generator.return`استفاده کنیم، همان مقدار را دوباره برمیگرداند.([MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/return)).
558
470
559
471
معمولا از آن استفاده نمیشود؛ چون اکثر زمانها میخواهیم تمام مقادیر را بگیریم، اما موقعی که بخواهیم در شرایط خاص generator را متوقف کنیم کاربرد دارد.
560
472
561
473
## خلاصه
562
474
563
475
- generatorها توسط تابع generator تولید میشوند. `{...} (...) function* f`
564
-
565
476
- عملگر yield (فقط) در داخل generatorها وجود دارد.
566
-
567
477
- کد بیرونی و generator ممکن است توسط `next/yield` با هم نتایج را رد و بدل کنند.
568
478
569
479
در جاوااسکریپت مدرن، generatorها کم استفاده میشوند. اما گاهی اوقات میتوانند مفید باشند؛ رد و بدل کردن داده با کد صدا زننده، یک قابلیت منحصر بفرد است. همچنین برای ساخت iterableها هم بکار میروند.
0 commit comments