Как мы можем использовать обещание в функции readline.on (Node.js 8. В настоящее время) - PullRequest
0 голосов
/ 29 января 2019

Невозможно использовать await / async в функции readline.on. Я не знаю, почему он не ждет, пока не вернутся результаты?также используется обещание под функцией ожидания, но бесполезно, когда я возвращаю обещание также бесполезно.Может кто-нибудь, кто эксперт в узле js, Es6 Пожалуйста, помогите мне, это моя скромная просьба ко всем разработчикам.Может ли кто-нибудь, пожалуйста, помогите мне решить эту проблему и спасибо заранее.

var readline = require('readline');
fs = require('fs');
redis = require('redis');

var redisClient = redis.createClient();

var filePath = './sample-data/whoodle_index_file_0.psv';

async function getSampleData() {
    let rl = readline.createInterface({
        input: fs.createReadStream(filePath),
        crlfDelay: Infinity
    });

    rl.on('line', async (line) => {

        let obj = {};
        let data = line.split('|');
        obj['name'] = data[0];

        console.log('first line of execution process');

        let result = await getDataFromRedisUsingKey(obj['name']);
        console.log('result' + result);
        console.log('secound line of execution process');
        console.log('want to use this results in to some other functions');

        let obj2 = {};
        obj2['name'] = data[3];

        console.log('third line of execution process');

        let result2 = await getDataFromRedisUsingKey(obj2['name']);
        console.log('result' + result);
        console.log('fourth line of execution process');
        console.log('want to use this results in to some other functions');

    });

}

getSampleData();

async function getDataFromRedisUsingKey(name) {
    return new Promise(function (resolve, reject) {
        redisClient.get(name, function (err, result) {
            console.log("result----------------------" + result);
            if (err) {
                reject();
            } else {
                resolve(result);
            }
        });
    });
}

Showing result like this on console 

first line of execution process
first line of execution process
result----------------------null
result----------------------null
resultnull
secound line of execution process
want to use this results in to some other functions
third line of execution process
resultnull
secound line of execution process
want to use this results in to some other functions
third line of execution process
result----------------------null
result----------------------null
result2null
fourth line of execution process
want to use this results in to some other functions
result2null
fourth line of execution process
want to use this results in to some other functions

But im expecting like this

first line of execution process
result----------------------null
resultnull
secound line of execution process
want to use this results in to some other functions
third line of execution process
result----------------------null
result2null
fourth line of execution process
want to use this results in to some other functions
first line of execution process
result----------------------null
resultnull
secound line of execution process
want to use this results in to some other functions
third line of execution process
result----------------------null
result2null
fourth line of execution process
want to use this results in to some other functions

Ответы [ 2 ]

0 голосов
/ 29 января 2019

Для чего это стоит, вот макет ожидаемого поведения, использующий массив обещаний в качестве «условия ожидания»:

// 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).

0 голосов
/ 29 января 2019

Скопируйте из комментария выше: Если я правильно понимаю, беспорядок вызван смешением обратного вызова и кода Promise: каждый асинхронный обратный вызов начинает выполняться в порядке события 'line' до первого await, а затем порядокнепредсказуемый, основанный на другом разрешении асинхронного Обещания.Если вы можете использовать Node.js 11, попробуйте переписать ваш код с помощью API асинхронных итераторов.Смотрите примеры здесь и здесь .

Я пытался переписать (исправление некоторых опечаток, таких как result2 вместо result в последнем блоке вывода).Этот код работает?

'use strict';

const readline = require('readline');
const fs = require('fs');
const redis = require('redis');

const redisClient = redis.createClient();

const filePath = './sample-data/whoodle_index_file_0.psv';

async function getSampleData() {
    const rl = readline.createInterface({
        input: fs.createReadStream(filePath),
        crlfDelay: Infinity
    });

    for await (const line of rl) {
        const obj = {};
        const data = line.split('|');
        obj['name'] = data[0];

        console.log('first line of execution process');

        const result = await getDataFromRedisUsingKey(obj['name']);
        console.log('result ' + result);
        console.log('secound line of execution process');
        console.log('want to use this results in to some other functions');

        const obj2 = {};
        obj2['name'] = data[3];

        console.log('third line of execution process');

        const result2 = await getDataFromRedisUsingKey(obj2['name']);
        console.log('result2 ' + result2);
        console.log('fourth line of execution process');
        console.log('want to use this results in to some other functions');
    }
}

getSampleData();

function getDataFromRedisUsingKey(name) {
    return new Promise(function (resolve, reject) {
        redisClient.get(name, function (err, result) {
            console.log('result----------------------' + result);
            if (err) {
                reject(err);
            } else {
                resolve(result);
            }
        });
    });
}
...