в чем разница между этими двумя асинхронными функциями в nodejs? - PullRequest
0 голосов
/ 25 августа 2018
const fs = require("fs");

fs.readFile("aa.js", () => {
  console.log("1");
  process.nextTick(() => {
    console.log("3");
  });
});

fs.readFile("aa.js", () => {
  console.log("2");
  process.nextTick(() => {
    console.log("4");
  });
});

// результат 1 3 2 4

const net = require("net");
const server = net.createServer(() => {}).listen(8080);

server.on("listening", () => {
  console.log("1");
  process.nextTick(() => {
    console.log("3");
  });
});

server.on("listening", () => {
  console.log("2");
  process.nextTick(() => {
    console.log("4");
  });
});

// результат 1 2 3 4

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

1 Ответ

0 голосов
/ 25 августа 2018

Первый - это гонка между двумя совершенно отдельными асинхронными fs.readFile() операциями. В зависимости от того, что выполнено первым, вероятно, получит оба журнала консоли раньше другого.Поскольку эти операции занимают некоторое измеримое количество времени, и они оба должны выполнять одинаковый объем работы, вполне вероятно, что тот, который вы начали первым, закончится первым, и это то, что вы видите.Но технически это неопределенная гонка между двумя асинхронными операциями, и они могут закончиться в любом порядке.Так как один может закончиться немного раньше другого, его обратный вызов завершения будет вызван раньше другого, и также вероятно, что 2-й еще не будет выполнен до того, как произойдет следующий тик, поэтому вы видите оба сообщения журнала от того, который одинфиниширует первым.

Ваш второй слушатель - два слушателя событий для одного и того же события. Таким образом, эти два слушателя гарантированно будут вызываться на один и тот же тик один за другим.Когда объект прослушивателя событий генерирует событие, он синхронно вызывает всех прослушивателей этого события один за другим, все на одном тике.Вот почему вы получаете 1, а затем 2 до 3 и 4, которые произойдут на будущих тиках.

Не следует путать объект eventEmitter с очередью событий.Это не одно и то же. В этом случае ваш серверный объект является подклассом eventEmitter.Какой-то внутренний код сервера решает отправить событие listening слушателям события сервераEmitter.Это решение об отправке события, вероятно, было результатом некоторой асинхронной операции, поступившей из очереди событий.Но для фактической передачи в eventEmitter это просто синхронные вызовы функций для зарегистрированных слушателей.Очередь событий не участвует в этом.Внутри кода eventEmitter, он буквально имеет цикл for, который перебирает соответствующие обработчики событий и вызывает каждый из них, один за другим.Вот почему вы получаете 1, затем 2.

На самом деле, вот ссылка на код внутри метода .emit() в определении класса EventEmitter, который показывает зацикливание через соответствующие слушателии звонить им синхронно.И вот фрагмент этого кода, вызывающий каждого слушателя один за другим:

const len = handler.length;
const listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
  Reflect.apply(listeners[i], this, args);

}

...