我们如何在(Node.js 8. 目前)上的 readline.on 函数下使用 promise

Posted

技术标签:

【中文标题】我们如何在(Node.js 8. 目前)上的 readline.on 函数下使用 promise【英文标题】:How can we use promise under readline.on function on (Node.js 8. Currently) 【发布时间】:2019-06-22 08:37:33 【问题描述】:

无法在 readline.on 函数下使用 await/async 我不知道为什么它不等到结果返回?在等待函数下也使用了promise,但是当我返回promise时也没有用。哪位精通node 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

【问题讨论】:

你忘了awaitPromise。您还应该 reject 处理错误,而不是 resolve 如果我创建一个具有某个名称的函数并将其粘贴新的承诺代码并使用 await 调用该函数也同样没有用,我的意思是 await 函数没有首先执行 如果您需要调试帮助,请发布该代码。 刚刚更新问题,请再次查看 你应该“回报”承诺 【参考方案1】:

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

// 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,然后检查是否有另一段代码请求处理 与此同时,rl 触发了另一个(或其他)"line" 事件,所以这是“请求处理的另一段代码”,因此 JS 执行它,直到它到达 await 或类似的 再次,在await 上,它会检查其要处理的事件队列,现在您猜猜如果rl 触发事件的速度比您的内部代码的第一个await 更快会发生什么:所有rl 的事件将在解释器时间排在第一位,您的所有内部代码都必须等待才能准备好处理它们的最后一段代码

然而,当 JS 再次开始处理你的内部代码时(即在 Redis 的 async 函数解析之后并且在任何先前注册的事件已经被处理之后),它会加载它的范围,所以你不必担心混合你的数据。唯一令人担忧的一点是检索该数据的顺序:如果需要,那么您必须明确考虑它,例如使用一个 promise 数组(因为数组中的 Promise 对象显然保持有序,无论这些对象的执行顺序如何承诺)。

【讨论】:

请注意,lockers.push(...) 是在 await Promise.all(lockers) 之后执行的,尽管我的代码内 cmets 可能暗示:这不是“现在我们等待”,它更像是“这里我们等”。这是同步的逐行代码中运算符(此处为括号)的经典优先级。 ;) 实际上我们有大量数据需要异步使用来检查是否存在相同的数据,然后我们需要跳过该行,这就是为什么我在数据库上使用 promise 检查每一行? 我不确定我是否理解您的限制,但您可能可以在最后“跳过”数据,或者使用 DB 语言区分重复项。但再说一遍:我不知道你的环境/要求! "rl.on('line', async () => " 行是否需要“async”?【参考方案2】:

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

我尝试重写(在最后一个输出块中修复了一些拼写错误,例如 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);
            
        );
    );

【讨论】:

我正在使用节点 8.9,它在 8.9 上给出错误等待(rl 的常量行) ^^^^^ SyntaxError: Unexpected reserved word, 所以它只能在节点 11.4 上工作?跨度> 不幸的是,似乎是这样,只是从 Node.js 11.4 开始。 是的,我只想要这个输出,但它只在 11.4v 上工作,但不幸的是我使用的是 8.9? 它也会发出这样的警告 (node:24105) ExperimentalWarning: Readable[Symbol.asyncIterator] 是一个实验性功能。此功能可能随时更改。所以它可能随时改变这个功能? 非常感谢@vsemozhetbyt,您尝试了很多,再次非常感谢您。如果您知道 8v 兼容的解决方案,请为我发布答案,谢谢。

以上是关于我们如何在(Node.js 8. 目前)上的 readline.on 函数下使用 promise的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MobileFirst Foundation 8 中使用 REST API 从 Node.js 发送推送通知?

如何让 EC2 上的 Node.js 服务器永远运行?

如何在 Ubuntu 上使用 pm2 和 Nginx 部署 Node.js 应用

如何在 Ubuntu 上使用 pm2 和 Nginx 部署 Node.js 应用

Node.js mysql 查询语法问题 UPDATE WHERE

CentOS 8.3上如何安装Node.js