简体   繁体   中英

Wrapping Event Handler in Promise

I have a file hosting an array of JSON objects. I want to insert those objects into a database. The insert is an async command that takes about a second to execute. The script should provide a count of records inserted. Created the following to simulate the problem:

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);
});

When I run the script, I don't get a total. The following is the output I get:

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!

The following is the contents for the sample data file (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"
    }
]

You are creating a race condition where your promise will resolve when the end event fires, which will probably be before all of your inserts are finished.

Since you're working with promises, you should wrap the insert operation in a promise, since that's asynchronous. Once you do that, you can maintain an array of promises that you can use in resolving the outer promise.

Please try this:

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);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM