Для чего это стоит, вот макет ожидаемого поведения, использующий массив обещаний в качестве «условия ожидания»:
// mock-up rl
const EventEmitter = require('events');
const rl = new EventEmitter();
// mock-up the getDataFromRedis thing: this gives a Promise that is fulfilled after 1s
function doSomething() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
}
// "waiting condition" variable
const lockers = [];
rl.on('line', async () => {
// wrap the code in a Promise that we add as a waiting condition
lockers.push(new Promise(async (resolve, reject) => {
// now we wait for all previously registered conditions to be OK before going on
await Promise.all(lockers);
// now we do the code with Redis
console.log('x1');
const r1 = await doSomething();
console.log('x2');
const r2 = await doSomething();
// finally we resolve the current Promise to release lock on following processes
resolve();
}));
});
// start the process: mock-up rl's behavior: fire several events in a row
for (let i = 0; i < 10; i++) {
rl.emit('line');
}
Однако эта архитектура действительно странная: почему вынужно "секвенировать" процесс?Я имею в виду: даже если все идет параллельно, вы все равно можете получить упорядоченные данные в конце, предполагая, что вы его кодируете!
Чтобы объяснить, что происходит под капотом:
rl
fires "line"
- JS вызывает слушателя к этому событию, и, как хороший однопоточный язык, основанный на событиях, он выполняет код слушателя, пока не достигнет первого
await
, затем проверяетесли другой фрагмент кода запрашивает обработку - в то же время,
rl
инициирует другое (или какое-либо другое) событие "line"
, так что это «еще один фрагмент кода, который запрашивает обработку», поэтому JS выполняет его,пока он не достигнет await
или подобного - снова, на
await
он будет проверять свою очередь событий для обработки, и теперь вы будете догадываться, что произойдет, если rl
запускает события быстрее, чем ваш внутреннийпервый код await
: все события rl
будут первыми в очереди на время интерпретатора, и весь ваш внутренний код должен будет подождать, прежде чем будет готов обработать свои последние биты кода
Однако, когда JS снова начинает обработку вашего внутреннего кода (т.е. после разрешения асинхронной функции Redis и после обработки любого ранее зарегистрированного события), он загружает его со своей областью, так что вам не нужно беспокоиться осмешивая ваши данные.Единственным беспокойным моментом является получение порядка этих данных: при необходимости вы должны явно рассмотреть это, например, используя массив обещаний (поскольку объекты Promise в массиве, очевидно, остаются в порядке, независимо от порядка их выполнения.Promises).