כדי לקרוא קלט מהמשתמש ב-Node.js, צרו ממשק readline על process.stdin ושאלו עם rl.question(). ב-Node.js אין prompt(): הגרסה של הדפדפן פותחת חלון דו-שיח, ולתוכנית טרמינל אין כזה. הצורה המודרנית משתמשת ב-readline/promises, שבה await rl.question('Name? ') מחזיר את השורה שהמשתמש הקליד. סגרו את הממשק כשסיימתם, אחרת התוכנית ממשיכה לחכות לעוד קלט.
question() הדפיס את השאלה שלו, חיכה לשורת קלט אחת והחזיר אותה בלי תו השורה החדשה, ולכן התוכנית הדפיסה Next year you will be 37. לכמה שאלות, חכו ל-question() אחד אחרי השני.
question() של readline עם callback
ה-API המקורי, שקיים בכל גרסה של Node.js, מעביר את התשובה ל-callback. שאלות מקוננות פירושן callbacks מקוננים:
הוא הדפיס את השאלה, ואז You picked blue. התשובה היא מחרוזת רגילה, אז עשו לה trim לפני השוואה: משתמש שמקליד רווח אחרי המילה יקבל אחרת 'blue ', שאינו שווה ל-'blue'.
קריאת קלט שורה אחרי שורה
כדי לעבד כל שורה עד שהקלט נגמר, עברו על הממשק עם for await. כך תוכנית קוראת רשימה שהמשתמש מקליד (ומסיים עם Ctrl+D) או קובץ שמועבר אליה ב-pipe עם node index.js < numbers.txt. קוד ישן יותר עושה את אותו הדבר עם אירועים, rl.on('line', fn) לכל שורה ו-rl.on('close', fn) בסוף; הלולאה היא אותו זוג אירועים, כתוב מלמעלה למטה:
הוא הדפיס 3 numbers, total 49, והלולאה הסתיימה מעצמה כשהקלט נגמר, כך שאין צורך ב-close(). הוסיפו שורת קלט רביעית, 1, והתוצאה תהיה 4 numbers, total 50.
קריאת כל ה-stdin בבת אחת
לקלט שמגיע ב-pipe מתוכנית אחרת (cat data.txt | node index.js), פשוט יותר לקרוא הכל בקריאה אחת. File descriptor 0 הוא הקלט הסטנדרטי. קובץ שנשמר ב-Windows עלול לסיים שורות ב-\r\n, אז פצלו לפי /\r?\n/ כשהקלט יכול להגיע משם:
הוא הדפיס את שלושת הפריטים בעמודה. readFileSync(0) חוסם עד שהקלט מושלם, וזה בסדר לסקריפט שקורא pipe ולבדיקות, אבל שגוי לכלי אינטראקטיבי, שבו המשתמש היה מקליד הכל לפני שהוא רואה שאלה כלשהי.
במה להשתמש
כל הארבע קוראות את אותו קלט סטנדרטי. ההבדל הוא מתי הקוד שלכם מקבל את הטקסט: תשובה אחת בכל פעם, שורה אחת בכל פעם, או הכל בסוף.
| צורך | השתמשו ב |
|---|---|
| לשאול כמה שאלות לפי הסדר | readline/promises עם await rl.question() |
| לתמוך בגרסאות Node.js שלפני 17 | readline עם callback של question() |
| לטפל בכל שורה כשהיא מגיעה | for await (const line of rl) |
| לקרוא pipe או קובץ שלם מ-stdin | fs.readFileSync(0, 'utf8') |
| ערכים שידועים לפני שהתוכנית מתחילה | process.argv במקום |
טעויות נפוצות
לשכוח את rl.close(). הממשק משאיר את הקלט הסטנדרטי פתוח, כך שהתוכנית לא יוצאת אף פעם אחרי השאלה האחרונה. סגרו אותו ברגע שיש לכם את כל התשובות.
להשתמש בתשובה כמספר. כמו כל מה שמוקלד בטרמינל, התשובה היא מחרוזת. '36' + 1 הוא '361'; המירו עם Number() קודם.
להעביר ב-pipe כמה תשובות לכמה שאלות. כשהקלט מגיע מ-pipe ולא מהמקלדת, readline קורא את כולו בבת אחת, ושורה שמגיעה לפני שה-question() שלה נשאל נזרקת. לקלט מ-pipe, השתמשו בלולאת for await או ב-readFileSync(0).
להשמיט את האפשרות output. בלי output: process.stdout, question() לא מדפיס את השאלה שלו אף פעם, והמשתמש בוהה בטרמינל ריק. הלולאה של שורה אחרי שורה לא צריכה אותה, כי היא לא מדפיסה כלום.
שאלות נפוצות
למה prompt לא מוגדר ב-Node.js?
prompt() היא פונקציה של הדפדפן שפותחת חלון דו-שיח, וב-Node.js אין חלון שבו אפשר לפתוח אותו. השתמשו ב-readline ב-Node.js, או בחבילה כמו prompts או inquirer בשביל תפריטים ושדות סיסמה.
איך קוראים סיסמה בלי להציג אותה?
readline מציג כל מקש שנלחץ. חבילות כמו prompts או @inquirer/password מסתירות את הקלט; לעשות את זה בעצמכם פירושו להעביר את הטרמינל ל-raw mode עם process.stdin.setRawMode(true) ולטפל בכל מקש.
להשתמש ב-readline או ב-process.argv?
השתמשו ב-process.argv כשהערכים ידועים לפני שהתוכנית מתחילה, כך שהיא יכולה לרוץ בסקריפט בלי שאדם נמצא מולה. השתמשו ב-readline בכלים אינטראקטיביים ששואלים שאלה אחרי שאלה.