shaun
shaun

Reputation: 1273

Async Await Promise.all Array.map not behaving as expected. Not Sure Why

I have the below in an async function in one of my projects. matchCamera, matchIP, and matchAudio all return either boolean, or an error.

If an error gets returned I would expect for it to fall into my master catch so I can handle it, but this isn't happening.

try {
    // .... Additional code here

    const typecheck = await Promise.all(
        evoCfg.cameras.map(async camera => {
            if (camera.type === 'H264') {
                return await matchCamera(camera);
            } else if (camera.type === 'RTSP') {
                return await matchIP(camera);
            } else if (camera.type === 'AUDIO') {
                return await matchAudio(camera);
            } else {
                // Motion JPEG
                return true;
            }
        })
    );

    //  .... additional code here

    console.log('results:);
    console.dir(typecheck, {depth: null, colors: true});
} catch (e) {
    console.error('In Master Catch:', e);
}

My output that I keep getting when I cause an error condition is:

results:
[ true,
true,
true,
true,
true,
true,
Error: MAC for IP Cam not found on Network: 00:11:22:33:44:55
  at matchIP (/file.js:58:15)
  at process._tickCallback (internal/process/next_tick.js:68:7),
true ]

I am expecting:

In Master Catch: MAC for IP Cam not found on Network: 00:11:22:33:44:55
  at matchIP (/file.js:58:15)
  at process._tickCallback (internal/process/next_tick.js:68:7)

const matchIP = async source => {
    let arpScan = [];

    for (const c in obj.arr){
        if(obj.arr[c].name === source.source) {
            try {
                arpScan = await scannerP();

                let arpIdx = searchObjArray(source.mac, source.mac, 'mac', 'mac', arpScan);
                if(arpIdx === -1) {
                    // not found on network
                    throw new Error(`MAC for IP Cam not found on Network: ${source.mac}`);
                }

                for (const cs in obj.arr[c].sources) {
                    if (
                        obj.arr[c].sources[cs].id === arpScan[arpIdx].mac &&
                        obj.arr[c].sources[cs].url === `rtsp://${arpScan[arpIdx].ip}/${source.streamPort}`
                        ) {
                        return true;
                    }
                }
                let recorderIdx = searchObjArray(
                    'rtsp',
                    source.mac,
                    'fmt',
                    'id',
                    obj.arr[c].sources
                );

                source.streamAddress = arpScan[arpIdx].ip;
                obj.arr[c].sources[recorderIdx].url = `rtsp://${arpScan[arpIdx].ip}/${source.streamPort}`;
                return false;
            } catch (e) {
                return e;
            }
        }
    }
};

Upvotes: 0

Views: 583

Answers (2)

Old Pro
Old Pro

Reputation: 25557

The problem is that your matchIP function has in it

try {
  // ... code
catch (e) {
  return e;
}

So it is returning the error as a value rather than throwing it for your outer block to catch.

Also, as other people have pointed out. You are mostly defeating the value of Promise.all by using await in your map function. Take the awaits out.

Upvotes: 1

kockburn
kockburn

Reputation: 17636

The Promise.all() method returns a single Promise that resolves when all of the promises passed as an iterable have resolved or when the iterable contains no promises. It rejects with the reason of the first promise that rejects.

You are defeating the purpose of Promise.all. It expects a list of promises, but you're giving a list of values from a promise.

const typecheckArray = await Promise.all(
  evoCfg.cameras.map(camera => {
    if (camera.type === 'H264') {
      return matchCamera(camera);
    } else if (camera.type === 'RTSP') {
      return matchIP(camera);
    } else if (camera.type === 'AUDIO') {
      return matchAudio(camera);
    } else {
      // Motion JPEG
      return Promise.resolve(true);
    }
  })
);

Also, Promise.all returns an array of values.

Upvotes: 1

Related Questions