обратные вызовы могут сбивать с толку, и давайте попробуем понять это на примере, не глядя на определение

давайте возьмем проблему, так как я хочу задать несколько вопросов пользователю, используя 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}`);
});

чем больше вы пытаетесь углубиться в этот код, тем больше вы увидите, насколько это правильное сочетание обратных вызовов с помощью стрелочных функций.

так что давайте шаг за шагом

  1. коллекции принимают массив вопросов и другую стрелочную функцию, которая будет вызываться позже
  2. при сборе ответов вызывается 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());