aboutsummaryrefslogtreecommitdiff
path: root/files/he/learn/javascript/asynchronous/promises/index.html
blob: 87c8839084d5b863d9593ff553e7207f3789666a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
---
title: Graceful asynchronous programming with Promises
slug: Learn/JavaScript/Asynchronous/Promises
translation_of: Learn/JavaScript/Asynchronous/Promises
---
<div>{{LearnSidebar}}</div>

<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</div>

<p class="summary"><span class="seoSummary"><strong>Promises</strong> הן תכונה חדשה יחסית ב-JavaScript, אשר מאפשרת לנו לדחות פעולות מסוייומות עד אשר פעולותדמות להן יושלמו, או שיגיבו לכך שהן נכשלו. זוהי תכונה מאוד שימושית על מנת ליצור רצף של פעולות א-סינכרוניות שיעבדו בצור הטובה. מאמר זה נועד להסביר כיצד promises עובדות, כיצד אנו נראה אותם בשימוש ב-web APIs וכיצד נכתוב promises משלנו. </span></p>

<table class="learn-box standard-table">
 <tbody>
  <tr>
   <th scope="row">ידע מוקדם:</th>
   <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td>
  </tr>
  <tr>
   <th scope="row">מטרה:</th>
   <td>להבין מהן promises וכיצד להשתמש בהן.</td>
  </tr>
 </tbody>
</table>

<h2 id="מהן_promises">מהן promises?</h2>

<p>סקרנו קצת <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> במאמר הראשון במודול זה, אבל במאמר זה נסקור אותן יותר לעומק.?</p>

<p>בעיקרון promise הוא בעצם אובייקט שמייצג מצב ביניים של פעולה - בפועל, promise היא מעין הבטחה שתוצאה מסויימת תוחזר בנקודה מסויימת בעתיד. אין שום הבטחה מתי הפעולה תושלם ומתי התוצאה תוחזר, אבל יש הבטחה שכאשר התוצאה מוכנה, או שכאשר הפעוללה נכשלה, הקוד שסיפקנו ירוץ על מנת לעשות משהו עם תוצאה מוצלחת או להתמודד עם כשלון בפעולה.</p>

<p>באופן כללי, אנחנו פחות מתעניינים בזמן שייקח לפעולה א-סינכרונית להחזיר את התוצאה שלה (אלא אם כן מדובר בזמן יותר מדי ארוך), ואנחנו יותר מעוניינים בכך שתהיה לנו אפשרות להגיב לאותה תגובה כאשר היא תחזור, לא משנה מהי התגובה. וכמובן, זה נחמד שאותה פעולה לא חוסמת את הקוד מלרוץ.</p>

<p>אחד מהשימושים של promise שאנחנו נראה הוא ב-web APIs שמחזירים promise. נניח ויש לנו יישום וידאו צ׳אט. ליישום זה יש חלון עם רשימת החברים של המשתמש, ובלחיצה על כפתור ליד שם החבר, תחל שיחת וידאו עם אותו חבר.</p>

<p>מטפל האירוע של הכפתור הזה קורא ל- {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} על מנת לקבל גישה למיקרופון ולמצלמה של המשתמש. מאחר ו-<code>()getUserMedia</code> חייב לוודא שלמשתמש יש אישור להשתמש באותם מכשירים ולבקש מהמשתמש לבחור איזה מיקרופון ואיזו מצלמה להשתמש בהם או בכל שילוב אחר. בזמן הבקשה הזו, פעולה זו יכולה לחסום את המשך התוכנית לא רק עד אשר כל האישורים האלו התקבלו, אלא גם עד אשר המצלמה והמיקרופון יתחברו. בנוסף, המשתמש אולי לא יגיב באופן מיידי לבקשות אלו. זה יכול לקחת הרבה זמן.</p>

<p>מאחר והקריאה ל- <code>()getUserMedia</code> נעשית מה- browser's main thread, הדפדפן חסום עד אשר <code>()getUserMedia</code> תסיים. ברור כמובן שזו לא אפשרות מקובלת בימים אלו. ללא promises, כל דבר בדפדפן היה נהפך ללא שימושי עד אשר המשתמש יחליט מה לעשות עם המצלמה והמיקרופון. אז במקום לחכות למשתמש, לקבל את המכשירים שנבחרו, ולהחזיר את ה-{{domxref("MediaStream")}} שנוצר למקורות אלו, <code>()getUserMedia</code> מחזיר {{jsxref("promise")}} אשר נפתר עם {{domxref("MediaStream")}} ברגע שהוא זמין.</p>

<p>הקוד של יישום הוידאו צאט שלנו, עשוי להיראות כך?:?</p>

<pre class="brush: js">function handleCallButton(evt) {
  setStatusMessage("Calling...");
  navigator.mediaDevices.getUserMedia({video: true, audio: true})
    .then(chatStream =&gt; {
      selfViewElem.srcObject = chatStream;
      chatStream.getTracks().forEach(track =&gt; myPeerConnection.addTrack(track, chatStream));
      setStatusMessage("Connected");
    }).catch(err =&gt; {
      setStatusMessage("Failed to connect");
    });
}
</pre>

<p>הפונקציה הזו מתחילה בכך שהיא משתמש בפונקציה שנקראת <code>()setStatusMessage</code> על מנת לעדכן שורת עדכון למשתמש עם הטקסט: "Calling...", שמעידה על כך שמבוצע ניסיול החל בשיחה. לאחר מכן היא קוראת לפונקציה <code>()getUserMedia</code>, ומבקשת שתחל בסטרים (stream) ?שיש לו גם וידאו וגם אודיו וברגע שהסטרים יהיה מוכן, היא ממשיכה בפעולות לשם הקמת הסטרים וחיבור המצלמה והאודיו. לאחר מכן היא מציגה למשתמש הודעה ״Connected״. </p>

<p>אם <code>()getUserMedia</code> תיכשל, בלוק הקוד של <code>catch</code> ירוץ. הוא משתמש שוב ב- <code>()setStatusMessage</code> על מנת להציג למשתמש שהתרחשה שגיאה. </p>

<p>הדבר החשוב כן הוא שהקריאה של <code>()getUserMedia</code> מוחזרת כמעט באופן מיידי, גם אם הסטרים של המצלמה לא התקבל עדיין. אפילו אם הפונקציה של <code>()handleCallButton</code> סיימה להריץ את הקוד שבתוכה והחזירה את השליטה לקוד שקרא לה, כאשר <code>()getUserMedia</code> תסיים את הפעולה שלה, בין אם בהצלחה ובין אם תתרחש שגיאה, פונקציה זו תקרא שוב לאותו מטפל אירוע שסיפקנו לה. כלומר, היישום ימשיך לעבוד ולא יחכה לזרם הוידאו ולא ימנע מיתר הקוד להמשיך לרוץ. </p>

<div class="blockIndicator note">
<p><strong>לתשומת לב:</strong>  לפרטים נוספים אודות נושא מורכב זה של וידאו ואודיו, ראו <a href="/docs/Web/API/WebRTC_API/Signaling_and_video_calling">Signaling and video calling</a>.</p>
</div>

<h2 id="הבעיה_עם_callbacks">הבעיה עם callbacks</h2>

<p>על מנת להבין לעומק מדוע promises הן דבר טוב, יעזור לנו לחשוב על ה-callbacks המיושנות ולהבין מדוע הן בעייתיות. </p>

<p>ננסה להמחיש זאת באמצעות דוגמא להזמנת פיצה כאנלוגיה. יש מספר שלבים שאנחנו צריכים לעשות ולהשלים בהצלחה, אשר לא ממש הגיוני לבצע אותם בסדר אחר או לבצע אותם בסדר הנכון, אבל בלי לחכות שהשלב הקודם הסתיים:</p>

<ol>
 <li>בחירת התוספות לפיצה - זה יכול לקחת זמן אם אנחנו לא ממש בטוחים איזו תוספת אנחנו רוצים על הפיצה ושלב זה יכול להיכשל אם בסופו של דבר לא קיבלנו החלטה איזו תוספת אנחנו רוצים, או אם בסוף החלטנו לאכול משהו אחר. </li>
 <li>בהנחה והחלטנו על תוספת, לאחר מכן אנחנו מבצעים הזמנה של הפיצה שאנחנו רוצים. שלב זה יכול לקחת זמן עד אשר הפיצה תהיה מוכנה, ואף יכול להיכשל אם לפיצרייה אין את המרכיבים הנכונים. </li>
 <li>בשלב האחרון אנחנו אוספים את הפיצה ואוכלים, גם שלב זה יכול להיכשל אם לא שילמנו לדוגמא על הפיצה או לא באנו לאסוף את הפיצה. </li>
</ol>

<p>עם ה-<a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#Callbacks">callbacks</a> הישנות, קוד מופשט שלנו ייראה בערך כך: </p>

<pre class="brush: js">chooseToppings(function(toppings) {
  placeOrder(toppings, function(order) {
    collectOrder(order, function(pizza) {
      eatPizza(pizza);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);</pre>

<p>קוד זה הוא מבולגן וקשה להבנה, ולפעמים גם נקרא כ-callback hell, הוא גם דורש שהפונקציה <code>()failureCallback</code> תיקרא כמה פעמים (בעבור כל פונקציה משורשרת) ויש לו גם חסרונות נוספים.</p>

<h3 id="שדרוג_עם_promises">שדרוג עם  promises</h3>

<p>Promises הופכות את סיטואציות כמו למעלה להרבה יותר פשוטות לכתיבה, פירוש וריצה. אם נציג את הקוד המופשט שלנו שוב באמצעות promises א-סינכרוניות, הוא ייראה כך:</p>

<pre class="brush: js">chooseToppings()
.then(function(toppings) {
  return placeOrder(toppings);
})
.then(function(order) {
  return collectOrder(order);
})
.then(function(pizza) {
  eatPizza(pizza);
})
.catch(failureCallback);</pre>

<p>זה כבר הרבה יותר טוב- הרבה יותר קל להבין מה קורה כאן והיינו צריכים רק בלוק קוד אחד של <code>()</code><code>catch.</code> בעבור כל השגיאות שאולי יתרחשו. כל הקוד הזה אינו חוסם את ה-main thread (כך שאנחנו יכולים להמשיך לראות טלווזיה עד אשר הפיצה תהיה מוכנה), וכל פעולה תחכה בוודאות עד אשר הפעולה הקודמת תסיים לפני שהיא תרוץ. אנחנו יכולים לקשור מספר פעולות א-סינכרוניות כך שיתרחשו אחת אחרי השנייה מכיוון שכל בלוק קוד של <code>(.....)then.</code> מחזיר promise חדשה, שנפתח כאשר הקוד שבתוך ה-<code>(.....)then.</code> הרלוונטי מסיים לרוץ. </p>

<p>באמצעות שימוש בפונקציות חץ (arrow functions), אנחנו אפילו יכולים להפוך את הקוד לעוד יותר פשוט: </p>



<pre class="brush: js">chooseToppings()
.then(toppings =&gt;
  placeOrder(toppings)
)
.then(order =&gt;
  collectOrder(order)
)
.then(pizza =&gt;
  eatPizza(pizza)
)
.catch(failureCallback);</pre>

<p>או אפילו בצורה הזו:</p>

<pre class="brush: js">chooseToppings()
.then(toppings =&gt; placeOrder(toppings))
.then(order =&gt; collectOrder(order))
.then(pizza =&gt; eatPizza(pizza))
.catch(failureCallback);</pre>

<p>זה עובד מכיוון שעם פונקציות חץ, <code>&lt;= ()</code> הוא סינטקסס חוקי והוא קיצור של <code>{return x} &lt;= ()</code>.</p>

<p>אנחנו אפילו יכולים לרשום את הקוד שלנו בצורה כזו, מאחר שהפונקציות רק מעביר את הארגומנטים שלהם בצורה ישירה, אין צורך באמת לשכבה נוספת של פונקציה:</p>

<pre class="brush: js">chooseToppings().then(placeOrder).then(collectOrder).then(eatPizza).catch(failureCallback);</pre>

<p>יחד עם זאת, סינטקס זה לא ניתן לשימוש שוב, ולא ממש ברור לקריאה. </p>

<div class="blockIndicator note">
<p><strong>לתשומת לב</strong>: אנחנו אפילו יכולים לעשות שיפורים נוספים בסינטקס באמצעות הסינטקס של <code>async</code>/<code>await</code>, אשר נסקור אותו בהמשך המודול.</p>
</div>

<p>בבסיס שלהן, promises דומות למאזיני אירוע - event lisenters אך עם הבדלים ביניהם:</p>

<ul>
 <li>promis יכולה להצליח או להיכשל רק פעם אחת. היא לא יכול הלהציח פעמיים או להיכשל פעמיים והיא לא יכולה לעבור ממצב של הצלחה למצב של כישולון או ההפך, ברגע שהפעולה הסתייימה. </li>
 <li>אם promise הצליחה או נכשלה ואלחר מכן אנחנו רוצים להוסיף success/failure callback, ה-callback הנכון הוא שייקרא, למרות שהאירוע עצמו התרחש לפני כן. </li>
</ul>

<h2 id="הסבר_של_הסינטקט_הבסיסי_של_promise">הסבר של הסינטקט הבסיסי של promise</h2>

<p>Promises חשובות מאוד להבנה מכיוון שמרבית ה-Web API המודרניים משתמשים בהן בעבור פונקציות שעלולות לבצע פעולות ארוכות. </p>

<p>בהמשך המאמר הזה אנחנו נראה כיצד לכתוב promises משלנו, אבל כאן אנחנו נסכתל על דוגמאות פשוטות שאנחנו ניתקל בהן ב-Web API שונים.</p>

<p>בדוגמא הראשונה שלנו, אנחנו נשתמש במתודת <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code>, על מנת להביא תמונה מהאינטרנט, במתודת {{domxref("Body.blob", "blob()")}} על מנת להמיר את התוכן הגולמי של התגובה שקיבלנו לאובייקט {{domxref("Blob")}} , ולאחר מכן נציג את אותו blob בתוך אלמנט {{htmlelement("img")}}. זהו מאוד דומה לדוגמא שהסתכלנו עליה ב<a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#Asynchronous_JavaScript">מאמר הראשון במודול</a>, אבל אנחנו נעשה את זה מעט שונה כך שאתם תבנו את ה-promise. </p>

<ol>
 <li>
  <p>ראשית, הורידו את ה-<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">HTML template</a> ואת ה-<a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">image file</a> שאנחנו נייבא. </p>
 </li>
 <li>
  <p>הוסיפו אלמנט {{htmlelement("script")}} בתחתית ה-{{htmlelement("body")}} בקובץ ה-HTML.</p>
 </li>
 <li>
  <p>בתוך האלמנט {{HTMLElement("script")}} , הוסיפו את השורה הבאה: </p>
 </li>
 <li>
  <pre class="brush: js">let promise = fetch('coffee.jpg');</pre>

  <p>שורה זו קוראת למתודת <code>()fetch</code> ומעבירה אליה כפרמטר את ה-URL של התמונה שאנחנו רוצים לייבא מהרשת. אנחנו מאחסנים את אובייקט ה-promise שיוחזר אלינו מ-<code>()fetch</code> בתוך משתנה שנקרא לו promise. כפי שאמרנו בעבר, האובייקט הזה מייצג מצב ביניים שבהתחלה הוא לא הצלחה ולא כישלון - מצב זה נקרא <strong>pending.</strong></p>
 </li>
 <li>על מנת להגיב להצלחה של הפעולה כאשר היא תקרה, במקרה הזה כאשר {{domxref("Response")}} תוחזר אלינו, אנחנו נפעיל את המתודת <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">()</a></code><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then.</a></code> של אובייקט ה-promise. ה-callback בתוך בלוק הקוד של <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">()</a></code><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then.</a></code> (שנקרא גם <strong>executor</strong>), ירוץ רק כאשר פעולת ה-promise תושלם בהצלחה ותחזיר אובייקט {{domxref("Response")}} - במונחי promise, כאשר ה-promise תגיע למצב של הושלמה, <strong>fulfilled</strong>. היא תעביר את האובייקט {{domxref("Response")}} כפרמטר. </li>
 <li>
  <div class="blockIndicator note">
  <p><strong>לתשומת לב</strong>: הדרך שבה הבלוק <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">()</a></code><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then.</a></code> עובד היא דומה לדרך שבה אנחנו מוסיפים מאזין אירוע - event listener - לאובייקט באמצעות המתודה <code>()AddEventListener</code>. מאזין האירוע לא ירוץ עד אשר האירוע יתרחש (ובאותה נשימה, כאשר ה-promise הושלמה בהצלחה). ההבדל העיקרי ביניהם הוא ש-<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">()</a></code><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then.</a></code> ירוץ רק פעם אחת בכל פעם שמשתמשים בו ואילו מאזין האירוע יכול להיות מופעל כמה פעמים. </p>
  </div>

  <p>אנחנו מייד נריץ את מתודת  <code>()blob</code> על התגובה הזו, על מנת לוודא שגוף התגובה הורד בהצלחה, וכאשר הוא זמין נהפוך אותו לאובייקט <code>Blob</code> שאנחנו יכולים לעשות איתו משהו. התוצאה של זה תוחזר לנו כך :</p>

  <pre class="brush: js">response =&gt; response.blob()</pre>

  <p>שזה קיצור של: </p>

  <pre class="brush: js">function(response) {
  return response.blob();
}</pre>

  <p>עד כאן עם ההסבר, אנא הוסיפו את הקוד הבא מתחת לשורה הראשונה של JavaScript: </p>

  <pre class="brush: js">let promise2 = promise.then(response =&gt; response.blob());</pre>
 </li>
 <li>
  <p>כל קריאה ל-<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">()</a></code><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then.</a></code> יוצרת promise חדשה. זהו מאוד שימושי - מכיוון שמתודת -  <code>()blob</code> מחזירה גם היא promise, אנחנו יכולים לטפל באובייקט ה-<code>Blob</code> שהיא מחזירה בעת ההשלמה שלו באמצעות הפעלה של מתודת <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">()</a></code><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then.</a></code> על ה-promise השנייה. מכיוון שאנחנו רוצים לעשות משהו קצת יותר מורכב לאותו blob מאשר רק להריץ מתודה אחת עליו ולהחזיר את התוצאה, אנחנו צריכים לעטוף את גוף הפונקצייה בסוגריים מסולסלות - אחרת זה יגרום לשגיאה. הוסיפו את השורה הבאה מתחת לקוד הנוכחי שלכם: </p>
 </li>
 <li>
  <pre class="brush: js">let promise3 = promise2.then(myBlob =&gt; {

})</pre>
 </li>
 <li>
  <p>כעת, נכניס את הקוד הבא שהוא הפונקציה שתופעל, לתוך הסוגריים המסולסלות:</p>

  <pre class="brush: js">let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);</pre>

  <p>מה שעשינו כאן אנחנו מריצים בעצם מריצים מתודת {{domxref("URL.createObjectURL()")}} , מעבירים אליה כפרמרט את ה-<code>Blob</code> שהוחזר אלינו כאשר ה-promise השנייה הושלמה. זה מחזיר לנו URL שמצביע על האובייקט. לאחר מכן יצרנו אלמנט {{htmlelement("img")}} , וקבענו את ה-<code>src</code> שלו שיהיה שווה ל-URL של האובייקט ושייכנו אותו ל-DOM, כך שהתמונה תוצג על גבי הדף. </p>
 </li>
</ol>

<p>אם תשמרו ותרעננו את הדף, אתם תראו שהתמונה מוצגת על גבי הדף. </p>

<div class="blockIndicator note">
<p><strong>לתשומת לב</strong>:  אתם בטח תשימו לב שדוגמאות אלו ארוכות מדי בשביל פעולה פשוטה שיכולנו לבצע באמצעות יצירת אלמנט <code>&lt;img&gt;</code> וקביעת ה-<code>src</code> שלו לאותו URL של התמונה במקום לעשות זאת באמצעות <code>()fetch</code> ובאמצעות <code>()blob</code>. יחד עם זאת, דוגמא זו נועדה על מנת להסביר בפשטות את תהליך ה-promises.</p>
</div>

<h3 id="תגובה_לכישלון">תגובה לכישלון </h3>

<p>יש משהו חסר בדוגמא שלנו - כרגע, אין משהו שמגדיר כיצד להתמודד עם שגיאה כאשר ה-promise נכשלת, או <strong>rejects</strong> במונחים של promises. אנחנו יכולים להוסיף טיפול בשגיאה באמצעות הרצת מתודת <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">()catch</a>.</code> של ה-promise הקודמת:</p>

<pre class="brush: js">let errorCase = promise3.catch(e =&gt; {
  console.log('There has been a problem with your fetch operation: ' + e.message);
});</pre>



<p>To see this in action, try misspelling the URL to the image and reloading the page. The error will be reported in the console of your browser's developer tools.</p>

<p>This doesn't do much more than it would if you just didn't bother including the <code>.catch()</code> block at all, but think about it — this allows us to control error handling exactly how we want. In a real app, your <code>.catch()</code> block could retry fetching the image, or show a default image, or prompt the user to provide a different image URL, or whatever.</p>

<div class="blockIndicator note">
<p><strong>Note</strong>: You can see <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/simple-fetch.html">our version of the example live</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch.html">source code</a> also).</p>
</div>

<h3 id="Chaining_the_blocks_together">Chaining the blocks together</h3>

<p>This is a very longhand way of writing this out; we've deliberately done this to help you understand what is going on clearly. As shown earlier on in the article, you can chain together <code>.then()</code> blocks (and also <code>.catch()</code> blocks). The above code could also be written like this (see also <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch-chained.html">simple-fetch-chained.html</a> on GitHub):</p>

<pre class="brush: js">fetch('coffee.jpg')
.then(response =&gt; response.blob())
.then(myBlob =&gt; {
  let objectURL = URL.createObjectURL(myBlob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
})
.catch(e =&gt; {
  console.log('There has been a problem with your fetch operation: ' + e.message);
});</pre>

<p>Bear in mind that the value returned by a fulfilled promise becomes the parameter passed to the next <code>.then()</code> block's executor function.</p>

<div class="blockIndicator note">
<p><strong>Note</strong>: <code>.then()</code>/<code>.catch()</code> blocks in promises are basically the async equivalent of a <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> block in sync code. Bear in mind that synchronous <code>try...catch</code> won't work in async code.</p>
</div>

<h2 id="Promise_terminology_recap">Promise terminology recap</h2>

<p>There was a lot to cover in the above section, so let's go back over it quickly to give you a <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises#Promise_terminology_recap">short guide that you can bookmark</a> and use to refresh your memory in the future. You should also go over the above section again a few more time to make sure these concepts stick.</p>

<ol>
 <li>When a promise is created, it is neither in a success or failure state. It is said to be <strong>pending</strong>.</li>
 <li>When a promise returns, it is said to be <strong>resolved</strong>.
  <ol>
   <li>A successfully resolved promise is said to be <strong>fulfilled</strong>. It returns a value, which can be accessed by chaining a <code>.then()</code> block onto the end of the promise chain. The executor function inside the <code>.then()</code> block will contain the promise's return value.</li>
   <li>An unsuccessful resolved promise is said to be <strong>rejected</strong>. It returns a <strong>reason</strong>, an error message stating why the promise was rejected. This reason can be accessed by chaining a <code>.catch()</code> block onto the end of the promise chain.</li>
  </ol>
 </li>
</ol>

<h2 id="Running_code_in_response_to_multiple_promises_fulfilling">Running code in response to multiple promises fulfilling</h2>

<p>The above example showed us some of the real basics of using promises. Now let's look at some more advanced features. For a start, chaining processes to occur one after the other is all fine, but what if you want to run some code only after a whole bunch of promises have <em>all</em> fulfilled?</p>

<p>You can do this with the ingeniously named <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> static method. This takes an array of promises as an input parameter and returns a new <code>Promise</code> object that will fulfill only if and when <em>all</em> promises in the array fulfill. It looks something like this:</p>

<pre class="brush: js">Promise.all([a, b, c]).then(values =&gt; {
  ...
});</pre>

<p>If they all fulfill, then chained <code>.then()</code> block's executor function will be passed an array containing all those results as a parameter. If any of the promises passed to <code>Promise.all()</code> reject, the whole block will reject.</p>

<p>This can be very useful. Imagine that we’re fetching information to dynamically populate a UI feature on our page with content. In many cases, it makes sense to receive all the data and only then show the complete content, rather than displaying partial information.</p>

<p>Let's build another example to show this in action.</p>

<ol>
 <li>
  <p>Download a fresh copy of our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">page template</a>, and again put a <code>&lt;script&gt;</code> element just before the closing <code>&lt;/body&gt;</code> tag.</p>
 </li>
 <li>
  <p>Download our source files (<a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">coffee.jpg</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/tea.jpg">tea.jpg</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/description.txt">description.txt</a>), or feel free to substitute your own.</p>
 </li>
 <li>
  <p>In our script we'll first define a function that returns the promises we want to send to <code>Promise.all()</code>. This would be easy if we just wanted to run the <code>Promise.all()</code> block in response to three <code>fetch()</code> operations completing. We could just do something like:</p>

  <pre class="brush: js">let a = fetch(url1);
let b = fetch(url2);
let c = fetch(url3);

Promise.all([a, b, c]).then(values =&gt; {
  ...
});</pre>

  <p>When the promise is fulfilled, the <code>values</code> passed into the fullfillment handler would contain three <code>Response</code> objects, one for each of the <code>fetch()</code> operations that have completed.</p>

  <p>However, we don't want to do this. Our code doesn't care when the <code>fetch()</code> operations are done. Instead, what we want is the loaded data. That means we want to run the <code>Promise.all()</code> block when we get back usable blobs representing the images, and a usable text string. We can write a function that does this; add the following inside your <code>&lt;script&gt;</code> element:</p>

  <pre class="brush: js">function fetchAndDecode(url, type) {
  return fetch(url).then(response =&gt; {
    if (type === 'blob') {
      return response.blob();
    } else if (type === 'text') {
      return response.text();
    }
  })
  .catch(e =&gt; {
    console.log('There has been a problem with your fetch operation: ' + e.message);
  });
}</pre>

  <p>This looks a bit complex, so let's run through it step by step:</p>

  <ol>
   <li>First of all we define the function, passing it a URL and a string representing the type of resource it is fetching.</li>
   <li>Inside the function body, we have a similar structure to what we saw in the first example — we call the <code>fetch()</code> function to fetch the resource at the specified URL, then chain it onto another promise that returns the decoded (or "read") response body. This was always the <code>blob()</code> method in the previous example.</li>
   <li>However, two things are different here:
    <ul>
     <li>First of all, the second promise we return is different depending on what the <code>type</code> value is. Inside the executor function we include a simple <code>if ... else if</code> statement to return a different promise depending on what type of file we need to decode (in this case we've got a choice of <code>blob</code> or <code>text</code>, but it would be easy to extend this to deal with other types as well).</li>
     <li>Second, we have added the <code>return</code> keyword before the <code>fetch()</code> call. The effect this has is to run the entire chain and then run the final result (i.e. the promise returned by <code>blob()</code> or <code>text()</code>) as the return value of the function we've just defined. In effect, the <code>return</code> statements pass the results back up the chain to the top.</li>
    </ul>
   </li>
   <li>
    <p>At the end of the block, we chain on a <code>.catch()</code> call, to handle any error cases that may come up with any of the promises passed in the array to <code>.all()</code>. If any of the promises reject, the catch block will let you know which one had a problem. The <code>.all()</code> block (see below) will still fulfill, but just won't display the resources that had problems. If you wanted the <code>.all</code> to reject, you'd have to chain the <code>.catch()</code> block on to the end of there instead.</p>
   </li>
  </ol>

  <p>The code inside the function body is async and promise-based, therefore in effect the entire function acts like a promise — convenient.</p>
 </li>
 <li>
  <p>Next, we call our function three times to begin the process of fetching and decoding the images and text, and store each of the returned promises in a variable. Add the following below your previous code:</p>

  <pre class="brush: js">let coffee = fetchAndDecode('coffee.jpg', 'blob');
let tea = fetchAndDecode('tea.jpg', 'blob');
let description = fetchAndDecode('description.txt', 'text');</pre>
 </li>
 <li>
  <p>Next, we will define a <code>Promise.all()</code> block to run some code only when all three of the promises stored above have successfully fulfilled. To begin with, add a block with an empty executor inside the <code>.then()</code> call, like so:</p>

  <pre class="brush: js">Promise.all([coffee, tea, description]).then(values =&gt; {

});</pre>

  <p>You can see that it takes an array containing the promises as a parameter. The executor will only run when all three promises resolve; when that happens, it will be passed an array containing the results from the individual promises (i.e. the decoded response bodies), kind of like [coffee-results, tea-results, description-results].</p>
 </li>
 <li>
  <p>Last of all, add the following inside the executor. Here we use some fairly simple sync code to store the results in separate variables (creating object URLs from the blobs), then display the images and text on the page.</p>

  <pre class="brush: js">console.log(values);
// Store each value returned from the promises in separate variables; create object URLs from the blobs
let objectURL1 = URL.createObjectURL(values[0]);
let objectURL2 = URL.createObjectURL(values[1]);
let descText = values[2];

// Display the images in &lt;img&gt; elements
let image1 = document.createElement('img');
let image2 = document.createElement('img');
image1.src = objectURL1;
image2.src = objectURL2;
document.body.appendChild(image1);
document.body.appendChild(image2);

// Display the text in a paragraph
let para = document.createElement('p');
para.textContent = descText;
document.body.appendChild(para);</pre>
 </li>
 <li>
  <p>Save and refresh and you should see your UI components all loaded, albeit in a not particularly attractive way!</p>
 </li>
</ol>

<p>The code we provided here for displaying the items is fairly rudimentary, but works as an explainer for now.</p>

<div class="blockIndicator note">
<p><strong>Note</strong>: If you get stuck, you can compare your version of the code to ours, to see what it is meant to look like — <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/promise-all.html">see it live</a>, and see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-all.html">source code</a>.</p>
</div>

<div class="blockIndicator note">
<p><strong>Note</strong>: If you were improving this code, you might want to loop through a list of items to display, fetching and decoding each one, and then loop through the results inside <code>Promise.all()</code>, running a different function to display each one depending on what the type of code was. This would make it work for any number of items, not just three.</p>

<p>In addition, you could determine what the type of file is being fetched without needing an explicit <code>type</code> property. You could for example check the {{HTTPHeader("Content-Type")}} HTTP header of the response in each case using <code><a href="/en-US/docs/Web/API/Headers/get">response.headers.get("content-type")</a></code>, and then react accordingly.</p>
</div>

<h2 id="Running_some_final_code_after_a_promise_fulfillsrejects">Running some final code after a promise fulfills/rejects</h2>

<p>There will be cases where you want to run a final block of code after a promise completes, regardless of whether it fulfilled or rejected. Previously you'd have to include the same code in both the <code>.then()</code> and <code>.catch()</code> callbacks, for example:</p>

<pre class="brush: js">myPromise
.then(response =&gt; {
  doSomething(response);
  runFinalCode();
})
.catch(e =&gt; {
  returnError(e);
  runFinalCode();
});</pre>

<p>In more recent modern browsers, the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally">.finally()</a></code> method is available, which can be chained onto the end of your regular promise chain allowing you to cut down on code repetition and do things more elegantly. The above code can now be written as follows:</p>

<pre class="brush: js">myPromise
.then(response =&gt; {
  doSomething(response);
})
.catch(e =&gt; {
  returnError(e);
})
.finally(() =&gt; {
  runFinalCode();
});</pre>

<p>For a real example, take a look at our <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/promise-finally.html">promise-finally.html demo</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-finally.html">source code</a> also). This works exactly the same as the <code>Promise.all()</code> demo we looked at in the above section, except that in the <code>fetchAndDecode()</code> function we chain a <code>finally()</code> call on to the end of the chain:</p>

<pre class="brush: js">function fetchAndDecode(url, type) {
  return fetch(url).then(response =&gt; {
    if(type === 'blob') {
      return response.blob();
    } else if(type === 'text') {
      return response.text();
    }
  })
  .catch(e =&gt; {
    console.log(`There has been a problem with your fetch operation for resource "${url}": ` + e.message);
  })
  .finally(() =&gt; {
    console.log(`fetch attempt for "${url}" finished.`);
  });
}</pre>

<p>This logs a simple message to the console to tell us when each fetch attempt has finished.</p>

<div class="blockIndicator note">
<p><strong>Note</strong>: <code>finally()</code> allows you to write async equivalents to try/catch/finally in async code.</p>
</div>

<h2 id="Building_your_own_custom_promises">Building your own custom promises</h2>

<p>The good news is that, in a way, you've already built your own promises. When you've chained multiple promises together with <code>.then()</code> blocks, or otherwise combined them to create custom functionality, you are already making your own custom async promise-based functions. Take our <code>fetchAndDecode()</code> function from the previous examples, for example.</p>

<p>Combining different promise-based APIs together to create custom functionality is by far the most common way you'll do custom things with promises, and shows the flexibility and power of basing most modern APIs around the same principle. There is another way, however.</p>

<h3 id="Using_the_Promise()_constructor">Using the Promise() constructor</h3>

<p>It is possible to build your own promises using the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code> constructor. The main situation in which you'll want to do this is when you've got code based on an an old-school asynchronous API that is not promise-based, which you want to promis-ify. This comes in handy when you need to use existing, older project code, libraries, or frameworks along with modern promise-based code.</p>

<p>Let's have a look at a simple example to get you started — here we wrap a <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> call with a promise — this runs a function after two seconds that resolves the promise (using the passed <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve">resolve()</a></code> call) with a string of "Success!".</p>

<pre class="brush: js">let timeoutPromise = new Promise((resolve, reject) =&gt; {
  setTimeout(function(){
    resolve('Success!');
  }, 2000);
});</pre>

<p><code>resolve()</code> and <code>reject()</code> are functions that you call to fulfill or reject the newly-created promise. In this case, the promise fulfills with a string of "Success!".</p>

<p>So when you call this promise, you can chain a <code>.then()</code> block onto the end of it and it will be passed a string of "Success!". In the below code we simply alert that message:</p>

<pre class="brush: js">timeoutPromise
.then((message) =&gt; {
   alert(message);
})</pre>

<p>or even just</p>

<pre class="brush: js">timeoutPromise.then(alert);
</pre>

<p>Try <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/custom-promise.html">running this live</a> to see the result (also see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">source code</a>).</p>

<p>The above example is not very flexible — the promise can only ever fulfill with a single string, and it doesn't have any kind of <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> condition specified (admittedly, <code>setTimeout()</code> doesn't really have a fail condition, so it doesn't matter for this simple example).</p>

<div class="blockIndicator note">
<p><strong>Note</strong>: Why <code>resolve()</code>, and not <code>fulfill()</code>? The answer we'll give you for now is <em>it's complicated</em>.</p>
</div>

<h3 id="Rejecting_a_custom_promise">Rejecting a custom promise</h3>

<p>We can create a promise that rejects using the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> method — just like <code>resolve()</code>, this takes a single value, but in this case it is the reason to reject with, i.e., the error that will be passed into the <code>.catch()</code> block.</p>

<p>Let's extend the previous example to have some <code>reject()</code> conditions as well as allowing different messages to be passed upon success.</p>

<p>Take a copy of the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">previous example</a>, and replace the existing <code>timeoutPromise()</code> definition with this:</p>

<pre class="brush: js">function timeoutPromise(message, interval) {
  return new Promise((resolve, reject) =&gt; {
    if (message === '' || typeof message !== 'string') {
      reject('Message is empty or not a string');
    } else if (interval &lt; 0 || typeof interval !== 'number') {
      reject('Interval is negative or not a number');
    } else {
      setTimeout(function(){
        resolve(message);
      }, interval);
    }
  });
};</pre>

<p>Here we are passing two arguments into a custom function — a message to do something with, and the time interval to pass before doing the thing. Inside the function we then return a new <code>Promise</code> object — invoking the function will return the promise we want to use.</p>

<p>Inside the Promise constructor, we do a number of checks inside <code>if ... else</code> structures:</p>

<ol>
 <li>First of all we check to see if the message is appropriate for being alerted. If it is an empty string or not a string at all, we reject the promise with a suitable error message.</li>
 <li>Next, we check to see if the interval is an appropriate interval value. If it is negative or not a number, we reject the promise with a suitable error message.</li>
 <li>Finally, if the parameters both look OK, we resolve the promise with the specified message after the specified interval has passed using <code>setTimeout()</code>.</li>
</ol>

<p>Since the <code>timeoutPromise()</code> function returns a <code>Promise</code>, we can chain <code>.then()</code>, <code>.catch()</code>, etc. onto it to make use of its functionality. Let's use it now — replace the previous <code>timeoutPromise</code> usage with this one:</p>

<pre class="brush: js">timeoutPromise('Hello there!', 1000)
.then(message =&gt; {
   alert(message);
})
.catch(e =&gt; {
  console.log('Error: ' + e);
});</pre>

<p>When you save and run the code as is, after one second you'll get the message alerted. Now try setting the message to an empty string or the interval to a negative number, for example, and you'll be able to see the promise reject with the appropriate error messages! You could also try doing something else with the resolved message rather than just alerting it.</p>

<div class="blockIndicator note">
<p><strong>Note</strong>: You can find our version of this example on GitHub as <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/custom-promise2.html">custom-promise2.html</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise2.html">source code</a>).</p>
</div>

<h3 id="A_more_real-world_example">A more real-world example</h3>

<p>The above example was kept deliberately simple to make the concepts easy to understand, but it is not really very async. The asynchronous nature is basically faked using <code>setTimeout()</code>, although it does still show that promises are useful for creating a custom function with sensible flow of operations, good error handling, etc.</p>

<p>One example we'd like to invite you to study, which does show a useful async application of the <code>Promise()</code> constructor, is <a href="https://github.com/jakearchibald/idb/">Jake Archibald's idb library</a>. This takes the <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>, which is an old-style callback-based API for storing and retrieving data on the client-side, and allows you to use it with promises. If you look at the <a href="https://github.com/jakearchibald/idb/blob/master/lib/idb.js">main library file</a> you'll see the same kind of techniques we discussed above being used there. The following block converts the basic request model used by many IndexedDB methods to use promises:</p>

<pre class="brush: js">function promisifyRequest(request) {
  return new Promise(function(resolve, reject) {
    request.onsuccess = function() {
      resolve(request.result);
    };

    request.onerror = function() {
      reject(request.error);
    };
  });
}</pre>

<p>This works by adding a couple of event handlers that fulfill and reject the promise at appropriate times:</p>

<ul>
 <li>When the <code><a href="/en-US/docs/Web/API/IDBRequest">request</a></code>'s <a href="/en-US/docs/Web/API/IDBRequest/success_event"><code>success</code> event</a> fires, the <code><a href="/en-US/docs/Web/API/IDBRequest/onsuccess">onsuccess</a></code> handler fulfills the promise with the request <code><a href="/en-US/docs/Web/API/IDBRequest/result">result</a></code>.</li>
 <li>When the <code><a href="/en-US/docs/Web/API/IDBRequest">request</a></code>'s <a href="/en-US/docs/Web/API/IDBRequest/error_event"><code>error</code> event</a> fires, the <code><a href="/en-US/docs/Web/API/IDBRequest/onerror">onerror</a></code> handler rejects the promise with the request <code><a href="/en-US/docs/Web/API/IDBRequest/error">error</a></code>.</li>
</ul>

<h2 id="Conclusion">Conclusion</h2>

<p>Promises are a good way to build asynchronous applications when we don’t know the return value of a function or how long it will take to return. They make it easier to express and reason about sequences of asynchronous operations without deeply nested callbacks, and they support a style of error handling that is similar to the synchronous <code>try...catch</code> statement.</p>

<p>Promises work in the latest versions of all modern browsers; the only place where promise support will be a problem is in Opera Mini and IE11 and earlier versions.</p>

<p>We didn't touch on all promise features in this article, just the most interesting and useful ones. As you start to learn more about promises, you'll come across further features and techniques.</p>

<p>Most modern Web APIs are promise-based, so you'll need to understand promises to get the most out of them. Among those APIs are <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a>, <a href="/en-US/docs/Web/API/Web_Audio_API">Web Audio API</a>, <a href="/en-US/docs/Web/API/Media_Streams_API">Media Capture and Streams</a>, and many more. Promises will be more and more important as time goes on, so learning to use and understand them is an important step in learning modern JavaScript.</p>

<h2 id="See_also">See also</h2>

<ul>
 <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code></li>
 <li><a href="/en-US/docs/Web/JavaScript/Guide/Using_promises">Using promises</a></li>
 <li><a href="https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">We have a problem with promises</a> by Nolan Lawson</li>
</ul>

<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</p>

<h2 id="במודול_זה">במודול זה</h2>

<ul>
 <li><a href="/he/docs/Learn/JavaScript/Asynchronous/Concepts">עקרונות תכנות א-סינכרוני כלליים</a></li>
 <li><a href="/he/docs/Learn/JavaScript/Asynchronous/Introducing">הצגת asynchronous JavaScript</a></li>
 <li><a href="/he/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Asynchronous JavaScript: שימוש ב-Intervals ו-Timeouts</a></li>
 <li><a href="/he/docs/Learn/JavaScript/Asynchronous/Promises">טיפול בפעולות א-סינכרוניות באמצעות Promises</a></li>
 <li><a href="/he/docs/Learn/JavaScript/Asynchronous/Async_await">הפיכת Asynchronous Programming לקל יותר עם async ועם await</a></li>
 <li><a href="/he/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">בחירת האפשרות המתאימה</a></li>
</ul>