
readline מובנה ב-Node.js. יוצרים ממשק בעזרת readline.createInterface, ומגדירים לו קלט (process.stdin) ופלט (process.stdout). הקלט מגיע מהטרמינל, והפלט מוצג בטרמינל.questionquestion מציגה שאלה וממתינה לתשובה, אבל היא לא מחזירה ערך, והתשובה נקלטת בתוך callback. לכן אי אפשר לכתוב const name = question(...) כמו בשפות אחרות. אם הפונקציה הייתה סינכרונית, היא הייתה תוקעת את כל התוכנית עד שהמשתמש עונה.user-input.js: הפונקציה getUserInput(text) מחזירה Promise. בתוכה קוראים ל-question, ובתשובה קוראים ל-resolve עם מה שהמשתמש הקליד.closeUI: סוגרת את הממשק, כדי שהתוכנית תסתיים.module.exports.doWork מוגדרת כ-async, וכל שדה נקלט בעזרת await: שם פרטי, שם משפחה, אימייל וטלפון, כל אחד עם שאלה משלו. בסוף מציגים את הערכים וקוראים ל-closeUI. הקוד נשאר קריא גם עם ארבע שאלות, בלי Callback Hell.async/await במקום אחד.הטקסט המלא של הדקות הראשונות בהרצאה «הדגמה של תכנות אסינכרוני עם async» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
בואו ניישם את מה שלמדנו על מקרה אמיתי שיכול להיות בנואו ג'ייס. אז אנחנו רוצים לקלוט מידע מהמשתמש כרגע, נניח.
איך אנחנו עושים את זה? הרי נואו ג'ייס זה מערכת שאמורה להיות בצד של הסרבר סייד, בצד השרת. בצד השרת לא יושב שם המשתמש ומכניס לנו קלט לתוכנית.
בצד השרת אנחנו מקבלים את הבקשות מסרוויסים אחרים, מה-client side, כלומר מהדפדפן. אבל בואו נניח שאנחנו בונים כרגע דוגמה ב-node.js של אפליקציה שהיא לא בהכרח server side אלא רצה בצד הלקוח ואנחנו כן רוצים שהלקוח יכניס לנו מידע מהטרמינל שלו.
אז ב-node.js יש לנו איזשהו פאקדג' שנקרא read line. בואו ניקח require read line וזה פאקדג' בילד אין ב-node.js.
בשביל לעבוד איתו אנחנו צריכים להגדיר לו איזושהי פקודת קונפיגורציה. בואו נפתח משתנה, נקרא לו UI ובעצם היוזר אינטרפייס או הטרמינל או משהו כזה.
readline.createinterface זה פקודת קונפיגורציה. היא מקבלת אובייקט שבו אנחנו מגדירים input ואנחנו אומרים לו מאיפה אנחנו רוצים לקבל את ה input.
אנחנו רוצים לקבל את האינפוט מהטרמינל והטרמינל מוגדר כסטנדרט אינפוט של המערכת. סטנדרט אינפוט זה נמצא בפרוסס נקודה std-in, std-in זה כתבור של סטנדרט אינפוט, זאת אומרת הסטנדרט אינפוט של המערכת זה זה והוא אוטומטית מוגדר לטרמינל.
אותו הדבר אנחנו צריכים להגיד לו מהאוטפוט לאן להציג את המידע וזה יהיה הסטנדרט Output. הסטנדרט Output ב-Node.js נמצא ב-Process.std Out, והסטנדרט Output זה כמובן גם הטרמינל.
אז זו הגדרה קונפיגרטיבית כזאת שאומרת ל-ReadLine שאנחנו קולטים את המידע מפה ושולחים בחזרה את המידע לטרמינל. טוב, אז איך אנחנו עובדים איתו?
עכשיו, אם הייתי רוצה לעבוד איתו בצורה סטנדרטית רגילה, הייתי פשוט הולך ל-UI, יוזר אינטרפייס, ופונה לפונקציה שנקראת question, כאילו שאני שואל את היוזר שאלה, והוא מצפה לתשובה.
לדוגמה, enter your first name. נניח שאני רוצה לקלוט מהיוזר שם פרטי, שם משפחה, אימייל וטלפון. מאוד פשוט. אבל מה הבעיה?
הבעיה היא שהפונקציה question צריכה להמתין עד שהיוזר יואיל בטובו לבוא לפה ולהכניס לי את התוצאה אז אם היא צריכה להמתין והיא לא הייתה אסינכרונית אז היא הייתה תוקעת את הזרימה של Node.js וכל האפליקציה הייתה עוצרת ולא נותנת אפשרות לאף לקוח אחר נניח שהיינו בצד השחת אף לקוח אחר לעבוד עם Node.js וזה לא משהו שיכול להיות לכן הפונקציה הזאת
שימו לב מה היא מחזירה לנו היא מחזירה לנו void והיה הגיוני כאילו שהייתי פועל בצורה כזאת, const first name שווה. זאת בעצם קריאה רגילה של FAT C-Sharp או שפת Java, ששם אין בעיה להגיד למשתמש, תביא לי את השם הפרטי, הופה, אני קולט אותו לתוך משתנה.
אני לא יכול לעבוד בצורה כזאת ב-JavaScript ולא ב-Node.js. אז מה שאנחנו רואים כאן זה שיש פה callback שמתקבלת. למעשה זה אחד המקרים הבודדים שהוא לא מצפה לקבל ארור ואז סקסס, אלא אומר לי תביא לי רק callback אחד.
והcallback בעצם, בואו נראה מה הוא אומר, הוא מקבל את התשובה מהיוזר, שזה ה-string. זאת אומרת שה-first name שנשלח, שמתקבל מהיוזר, נשלח ל-callback הזאת.
אם עכשיו אני כאן אציג console.log את ה-first name, אז אנחנו נוכל לראות שהכל עובד כמו שצריך. Node, App, Go, Enter your first name, שימו לב שהמערכת ממתינה, אבל הוא לא עצר לנו את הריצה של התוכנית,
אנחנו יכולים תכף לראות את זה, הקוד הזה הוא הסינכרוני. אני מכניס מוישה, Enter, והנה first name מוישה. בואו נרשום פה console.log end of app.js.
נריץ את זה שוב פעם, ונראה Enter your first name, of app.js זאת אומרת שהוא לא המתין פה הוא המשיך והדפיס לנו את זה יוזר מכניס מוישה והנה אנחנו רואים first name מוישה כי רק אז הפונקציה הזאת מתבצעת אני כרגע יוריד את ה-end of app.js בשביל שהוא לא יפריע לנו
אבל אני מזכיר אני לא רציתי לקבל רק first name אני רוצה לקבל גם last name גם אימייל וגם פון, אז מה אני צריך לעשות? אני לא יכול כאן לדרוש גם את ה-first name, מפני שזה היה סינכרוני, אני רוצה כאן את ה-last name.
אני רוצה לבקש את ה-last name רק אחרי שהוא יביא לי את ה-first name. אז מה אנחנו עושים? אם הייתי משכפל את זה לכאן ואומר לו enter your last name, מקבל פה את ה-last name ואומר לו הנה ה-last name שלך, זה היה כמובן פועל בצורה לא טובה.
Enter your first name, first name מוישה, אוקיי, איפה ה-enter your last name? אני רואה שיש לי פה איזושהי בעיה עם הקוד הזה.
אז מה שאנחנו רוצים לעשות זה לומר לו עוד פעם שאנחנו רוצים את ה-last name רק אחרי שה-first name יתקבל, ואנחנו רוצים את ה-email רק אחרי שה-last name יתקבל.
הנה האימייל ואנחנו רוצים את הפון רק אחרי שהאימייל יתקבל ושימו לב מה קיבלנו callback hell יש לנו פה את הפון בצורה כזאת הנה כבר אנחנו מתחילים להתקל בcallback hell למרות שזה עובד זה עדיין לא אלגנטי לביצוע בואו נריץ את זה Node.go, enter your first name, enter your last name, או אני רואה שיש לי פה איזשהו
בלבול מפני שאני לא באמת רוצה להציג את last name כאן. אני רוצה להציג את כולם לפי הסדר רק כשהוא יסיים להכניס את ה-phone, ה-last name אני רוצה כאן, את ה-email אני רוצה כאן.
אוקיי, סידרנו קצת יותר טוב את הקטע קוד. בואו ננקה וננסה שוב פעם. Node App, Go. First name, מוישה.
Last name, אוף-ניק. E-mail, מוישה. את gmail ופון 52, Go. והנה יש לנו כל הפרטים מוצגים כמו שצריך.
שימו לב רק שהתוכנית לא הסתיימה בגלל שעדיין ה-UI תופס לנו את הסטנדרט output ואז ctrl c מסיים אותה אבל אם אני רוצה שהוא יסיים אוטומטית אני צריך לסגור את ה-ui הזה וזה יהיה על ידי ui.close רק כשהוא מסיים אני רוצה לסגור אותו לגמרי בואו רגע ננסה את זה node up a b c d והנה אנחנו רואים שהוא גם סיים לנו את התוכנית אבל אני רוצה לטפל בקולבאק הל הזה.
אז לצורך טיפול בקולבאק הל בואו נוציא את כל זה לפונקציה שמחזירה פרומיס. האמת, אנחנו רוצים להחזיר פרומיס רק מפונקציה אחת וזה לא מהפונקציה הזאת, אבל בואו נסדר את זה. ניקח כאן קובץ חדש, נקרא לקובץ הזה user input ונקודת שי-אס.
מה אנחנו צריכים להעתיק אליו? בואו ניקח את זה, נעתיק לפה. בואו ניקח ונבנה כאן פאנקשן אבל היא מחזירה פרומיס. פאנקשן, היא מקבלת את אותו שאלה להצגה או את הטקסט להצגה.
טקסט to show ומחזירה new promise. הפרומיס עצמו מקבל כאן את ה-resolve וה-reject, ומה שהוא מבצע זה את ה-UI נקודה ויש לנו פה את ה-Question.
הנה ה-Question, Text to show, זה בעצם מה אני מבקש מהיוזר, ואז כאן אני מקבל את ה-Result מהיוזר, זה ה-String Result.
מה אני רוצה לעשות ב-String Result? מה שאני רוצה לעשות ב-String Result זה לדווח אותו ב-Resolve, נקרא לזה User Answer, יותר טוב.
יש לנו פה resolve user answer והתשובה של היוזר.