• בלוג
  • שאלות מראיונות עבודה: לולאה אסינכרונית ב JS

שאלות מראיונות עבודה: לולאה אסינכרונית ב JS

פוסט זה כולל טיפ קצר בנושא פיתוח Front End. אם אתם רוצים ללמוד יותר לעומק על פיתוח Front End מהבסיס ועד הנושאים המתקדמים תשמחו לשמוע שבניתי קורס וידאו מקיף בנושא זה הכולל מעל 50 שיעורי וידאו והמון תרגול מעשי.
למידע נוסף והצטרפות לקורס בקרו בדף קורס Front End באתר.
 

הנה שאלה פשוטה שתעזור לכם להבין האם המתכנת שעומד מולכם מבין את המשמעות של עבודה עם קוד אסינכרוני ואת ההמרה בין חשיבה סינכרונית לאסינכרונית.

תוכן עניינים

  1. השאלה
  2. פתרון

1. השאלה

נתון הקוד הבא:

for ( var i=0; i < 10; i++ ) {
	var n = Math.random();
	if ( n > 0.8 ) {
		console.log('Found It: ' + n);
		break;		
	}
}

if ( i < 10 ) {
	console.log("Found the number in " + (i + 1) +  " iterations");
} else {
	console.log("Didn't find the number");
}

הקוד מגריל מספרים בלולאה עד שיגיע למספר הגדול מ 0.8, אך בכל מקרה אם לא מצא לאחר 10 נסיונות יוותר וידפיס הודעה מתאימה.

לאחר Security Audit של המערכת קיבלנו המלצה להחליף את Math.random בפונקציה יותר מאובטחת, ואיש אבטחת המידע אף כתב עבורנו פונקציה חדשה ומטורפת שמגרילה מספר ממש אקראי. לפונקציה לוקח יותר זמן לעבוד ולכן היא פועלת בצורה אסינכרונית באמצעות Callback. כך למשל תשתמשו בה כדי להדפיס מספר אקראי יחיד:

genRandomNumber(function(result) {
   console.log(result); 
});

עדכנו את הלולאה כך שתשתמש בפונקציה החדשה.

2. פתרון

המעבר מקוד סינכרוני לאסינכרוני מחייב שינוי מחשבתי. כבר אי אפשר להשתמש בלולאת for מאחר והלולאה תסתיים לפני שנדע מה היה המספר שהוגרל. במקום זאת, נצטרך להחליט האם להמשיך לאיטרציה הבאה או לא רק אחרי שקיבלנו את המספר האקראי, כלומר בתוך ה Callback. 

הדרך ב JS לבצע זאת היא לבנות פונקציית לולאה שתשתמש ב setTimeout עם זמן המתנה 0 כדי להפעיל את עצמה שוב ושוב (במידה ויש צורך). השימוש ב setTimeout מונע העמסת פריימים על המחסנית, ואילו אינדקס הלולאה הרץ נשמר כפרמטר שעובר לפונקציה בכל הפעלה.

כך נראה הקוד עבור הפתרון:

function loop(i) {
	if ( i <= 0 ) {
		console.log("Didn't find the number");
	} else {
		genRandomNumber(function(result) {
			if ( result > 0.8 ) {
				console.log("Found the number " + result + " in " + (11-i) + " iterations");
			} else {
				setTimeout(function() {
					loop(i-1);
				}, 0);
			}
		});
	}
}

loop(10);