我们如何在Node.js 8的readline.on函数下使用Promise。

时间:2019-01-29 09:07:18

标签: javascript node.js ecmascript-6 es6-promise

不能在readline.on函数下使用await / async我不知道为什么它不等到结果返回?在await函数下也使用了promise,但是当我返回promise时也没有用。节点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 :(得分:1)

从上面的评论中复制:如果我理解正确,那么混乱是由回调和Promise代码混合引起的:每个异步回调都按'line'事件的顺序开始执行,直到第一个await和那么基于其他异步Promise解决方案,订单是不可预测的。如果可以使用Node.js 11,请尝试使用异步迭代器API重写代码。请参见示例herehere

我试图重写(在最后一个输出块中修复了一些像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);
            }
        });
    });
}

答案 1 :(得分:1)

对于它的价值,这里是预期行为的模型,使用一个promise作为“等待条件”:

// 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触发"line"
  • JS调用该事件的侦听器,作为一种基于事件的单线程语言,它执行侦听器的代码,直到到达第一个await,然后检查是否有其他代码需要处理< / li>
  • 同时,rl触发了另一个(或其他)"line"事件,因此这是“另一条需要处理的代码”,因此JS会执行它,直到到达{{ 1}}之类的
  • 再次在await上检查要处理的事件队列,现在您猜测如果await触发事件的速度比内部代码的第一个rl快,会发生什么情况: await事件中的第一个在解释器时间排在第一位,并且您所有的内部代码都必须等待,然后才能准备好处理它们的最后一部分代码

但是,当JS重新开始处理您的内部代码时(即,在Redis的异步函数被解析之后,并且在任何先前注册的事件被处理之后),它将加载其作用域,因此您不必担心会混合数据。唯一令人担忧的一点是检索数据的顺序:如果需要,则必须明确地考虑它,例如使用一个promise数组(因为数组中的Promise对象显然保持顺序,无论这些对象的执行顺序如何承诺。)