обратные вызовы могут сбивать с толку, и давайте попробуем понять это на примере, не глядя на определение
давайте возьмем проблему, так как я хочу задать несколько вопросов пользователю, используя CLI, и в конце ответов я показываю ответы, сказанные им ... теперь есть какой-либо способ сделать это, но давайте посмотрим, как мы можем это сделать, используя обратные вызовы
const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const questions = [ "What is your name? ", "Where do you live? ", "What are you going to do with node js? " ]; const collectAnswers = (questions, done) => { const answers = []; const [firstQuestion] = questions; const questionAnswered = answer => { answers.push(answer); if (answers.length < questions.length) { rl.question(questions[answers.length], questionAnswered); } else { done(answers); } }; rl.question(firstQuestion, questionAnswered); }; collectAnswers(questions, answers => { console.log("Thank you for your answers. "); console.log(answers); process.exit(); });
выглядит немного сложно, поэтому попробуйте вывести rl.question() как
const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question("How do you like Node? ", answer => { console.log(`Your answer: ${answer}`); });
чем больше вы пытаетесь углубиться в этот код, тем больше вы увидите, насколько это правильное сочетание обратных вызовов с помощью стрелочных функций.
так что давайте шаг за шагом
- коллекции принимают массив вопросов и другую стрелочную функцию, которая будет вызываться позже
- при сборе ответов вызывается
rl.question(firstQuestion, questionAnswered);
, и он берет первый элемент массива вопросов и принимает входные данные из cli и вызываетсяquestionAnswered
, а затем вопрос задается до тех пор, пока его длина не будет соответствовать массиву ответов, после чего он переходит к другому условию, и вот где он выходит из текущей функции, а затем эти
console.log("Thank you for your answers. "); console.log(answers); process.exit();
исполняется
теперь подходит к эмиттеру событий. Эта часть не требует пояснений, поэтому давайте изменим наш код, предоставив выходные данные в виде событий.
const readline = require("readline"); const { EventEmitter } = require("events"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const questions = [ "What is your name? ", "Where do you live? ", "What are you going to do with node js? " ]; const collectAnswers = (questions, done = f => f) => { const answers = []; const [firstQuestion] = questions; const emitter = new EventEmitter(); const questionAnswered = answer => { emitter.emit("answer", answer); answers.push(answer); if (answers.length < questions.length) { rl.question(questions[answers.length], questionAnswered); } else { emitter.emit("complete", answers); done(answers); } }; rl.question(firstQuestion, questionAnswered); return emitter; }; const answerEvents = collectAnswers(questions); answerEvents.on("answer", answer => console.log(`question answered: ${answer}`) ); answerEvents.on("complete", answers => { console.log("Thank you for your answers. "); console.log(answers); }); answerEvents.on("complete", () => process.exit());
еще несколько дополнений
const readline = require("readline"); const { EventEmitter } = require("events"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const collectAnswers = (questions, done = f => f) => { const answers = []; const [firstQuestion] = questions; const emitter = new EventEmitter(); const questionAnswered = answer => { emitter.emit("answer", answer); answers.push(answer); if (answers.length < questions.length) { emitter.emit("ask", questions[answers.length]); rl.question(questions[answers.length], questionAnswered); } else { emitter.emit("complete", answers); done(answers); } }; process.nextTick(() => { emitter.emit("ask", firstQuestion); rl.question(firstQuestion, questionAnswered); }); return emitter; }; const questions = [ "What is your name? ", "Where do you live? ", "What are you going to do with node js? " ]; const answerEvents = collectAnswers(questions); answerEvents.once("ask", () => console.log("started asking questions")); answerEvents.on("ask", question => console.log(` question asked: ${question}`) ); answerEvents.on("answer", answer => console.log(` question answered: ${answer}`) ); answerEvents.on("complete", answers => { console.log("Thank you for your answers. "); console.log(answers); }); answerEvents.on("complete", () => process.exit());