在Promise中包装事件处理程序

时间:2019-06-22 04:07:14

标签: javascript node.js

我有一个托管JSON对象数组的文件。我想将这些对象插入数据库。插入是一个异步命令,大约需要一秒钟才能执行。该脚本应提供插入记录的计数。创建了以下内容以模拟该问题:

const fs = require('fs');
const jstream = require('JSONStream');

new Promise((res, rej) => {
    let rec = 0;

    try {

        const stream = fs.createReadStream('./sample.json');
        console.log(1);
        const p = stream.pipe(jstream.parse('*'))

        p.on('data', (stuff) => {
            console.log(2);
            console.log("New Round");
            console.log(stuff);

            // Simulated database insert
            setTimeout(()=> rec++, 2000 );
        });

        p.on('end', (rec) => {
            console.log(3);
            res(rec);
        });

        p.on('error', (err) => {
            console.log(4);
            rej(err);
        })
    } catch (err) {
        console.log(5);
        rej(err);
    }
})
.then((count) => {
    console.log(6);
    console.log(count);
    console.log("Done loading!");
})
.catch((err) => {
    console.log(7);
    console.log(err);
});

运行脚本时,我没有得到总计。以下是我得到的输出:

1
2
New Round
{ _id: '15fb781a-d2fc-4429-82c7-8eb3e0a007b7', _name: 'bruce' }
2
New Round
{ _id: '02007ad3-2b25-46d9-a609-edacf9e151dc', _name: 'ken' }
2
New Round
{ _id: '18913a7a-18e6-484b-81cd-2f89f1558de1', _name: 'phil' }
2
New Round
{ _id: '3dab1d04-7263-41a6-ad1e-bfa9e201d377', _name: 'bob' }
2
New Round
{ _id: '9584fee5-3733-460d-a1bc-21c2ae47e78b', _name: 'luthor' }
2
New Round
{ _id: 'f676eea0-dfa2-44b5-8af7-28622b533eae', _name: 'jimmy' }
2
New Round
{ _id: 'd435a9dd-95e0-4a5f-b12f-781248fcefe4', _name: 'pauly' }
2
New Round
{ _id: '6b7d882c-7071-4cdf-8426-eb0ed25d2f02', _name: 'micky' }
3
6
undefined
Done loading!

以下是示例数据文件(sample.json)的内容:

[
    {
        "_id": "15fb781a-d2fc-4429-82c7-8eb3e0a007b7",
        "_name": "bruce"
    },
    {
        "_id": "02007ad3-2b25-46d9-a609-edacf9e151dc",
        "_name": "ken"
    },
    {
        "_id": "18913a7a-18e6-484b-81cd-2f89f1558de1",
        "_name": "phil"
    },
    {
        "_id": "3dab1d04-7263-41a6-ad1e-bfa9e201d377",
        "_name": "bob"
    },
    {
        "_id": "9584fee5-3733-460d-a1bc-21c2ae47e78b",
        "_name": "luthor"
    },
    {
        "_id": "f676eea0-dfa2-44b5-8af7-28622b533eae",
        "_name": "jimmy"
    },
    {
        "_id": "d435a9dd-95e0-4a5f-b12f-781248fcefe4",
        "_name": "pauly"
    },
    {
        "_id": "6b7d882c-7071-4cdf-8426-eb0ed25d2f02",
        "_name": "micky"
    }
]

1 个答案:

答案 0 :(得分:3)

您正在创建一种竞争条件,当end事件触发时,您的诺言将得以解决,该事件很可能会在所有插入操作完成之前发生。

由于您正在使用promise,因此您应该将insert操作包装在promise中,因为这是异步的。完成此操作后,您可以维护一系列可用于解决外部承诺的承诺。

请尝试以下操作:

const fs = require('fs');
const jstream = require('JSONStream');

// Simulated database insert
const insert = () => new Promise(res => setTimeout(res, 2000));

new Promise((res, rej) => {
    let promises = [];

    try {

        const stream = fs.createReadStream('./sample.json');
        console.log(1);
        const p = stream.pipe(jstream.parse('*'))

        p.on('data', (stuff) => {
            console.log(2);
            console.log("New Round");
            console.log(stuff);

            promises.push(insert());
        });

        p.on('end', () => {
            console.log(3);
            // v-- Resolve with a promise that waits for all 
            //     inserts to finish
            res(Promise.all(promises).then(a => a.length));
        });

        p.on('error', (err) => {
            console.log(4);
            rej(err);
        })
    } catch (err) {
        console.log(5);
        rej(err);
    }
})
.then((count) => {
    console.log(6);
    console.log(count);
    console.log("Done loading!");
})
.catch((err) => {
    console.log(7);
    console.log(err);
});