0

I am trying to stop a multi-step Promise execution. Basically, after Firebase returns a number to me, if snapshot.size === 0 there is no need to continue with the rest. I've tried return and I've tried throw but neither seem to stop the error from happening which is:

>  error TypeError: snapshot.map is not a function
>      at userSources.get.then.then.snapshot (/Users/username/Personal Projects/ionic-attempt1/functions/index.js:108:14)
>      at process._tickCallback (internal/process/next_tick.js:68:7)
>  (node:18880) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
>      at ServerResponse.setHeader (_http_outgoing.js:470:11)
>      at ServerResponse.header (/Users/username/Personal Projects/ionic-attempt1/functions/node_modules/express/lib/response.js:771:10)
>      at ServerResponse.send (/Users/username/Personal Projects/ionic-attempt1/functions/node_modules/express/lib/response.js:170:12)
>      at ServerResponse.json (/Users/username/Personal Projects/ionic-attempt1/functions/node_modules/express/lib/response.js:267:15)
>      at userSources.get.then.then.then.then.catch.error (/Users/username/Personal Projects/ionic-attempt1/functions/index.js:231:32)
>      at process._tickCallback (internal/process/next_tick.js:68:7)
>  (node:18880) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
>  (node:18880) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
i  functions: Finished "services" in ~1s

Now the first error TypeError: snapshot.map is not a function is actually in the next .then so it's something I don't even want to happen. The bottom part is what I don't like, talking about how promise rejections will terminatee the process.

Here is my code:

var sources = [];
        var userSources = firestore
            .collection('sources')
            .where('last_queried', '<', oneHourAgo)
            .where('enabled', '==', true)
            .where('uid', '==', uid);
    userSources
        .get()
        .then(snapshot => {
            if (snapshot.size === 0) {
                console.log('fetch: no sources found in the last hour.');
                return response.status(200).json({ message: 'No sources need updating' });
                //throw response.status(200).json({ message: 'No sources need updating' });
            }
            snapshot.forEach(doc => {
                var source = doc.data();

                // update last time checked
                firestore
                    .collection('sources')
                    .doc(doc.id)
                    .set({ last_queried: firebase.firestore.Timestamp.now() }, { merge: true });

                sources.push({
                    id: doc.id,
                    name: source.name,
                    access_token: source.access_token
                });
            });
            return sources;
        })
        .then(snapshot => {
            return Promise.all(
                snapshot.map(source => {

                // Omitting code here

                })
            );
        })
        .then(all_accounts => {
            console.log('all accounts retrieved.');

                // Omitting code here

            return accounts;
        })
        .then(accounts => {

            return response.status(200).json({ message: accountLength + ' accounts updated', accounts: accounts });

        })
        .catch(error => {
            console.log('error', error);
            return response.status(200).json({ message: 'Error: ' + error });
        });
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
Tyler C
  • 531
  • 1
  • 5
  • 12

1 Answers1

1

what happens is, it enters this case:

    .get()
    .then(snapshot => {
        if (snapshot.size === 0) {
            // the code touchs here, this function returns something that is not an array
            console.log('fetch: no sources found in the last hour.');
            return response.status(200).json({ message: 'No sources need updating' });
            //throw response.status(200).json({ message: 'No sources need updating' });
        }

in the next .then call you have this:

.then(snapshot => {
        // snapshot is not an array anymore, and that's causing TypeError: snapshot.map is not a function
        return Promise.all(
            snapshot.map(source => {

            // Omitting code here

            })
        );
    })

What you need is to change to some function like this inside the second .then

.then(snapshot => {
        if (!Array.isArray(snapshot)) {
           // do something here
        }
        return Promise.all(
            snapshot.map(source => {

            // Omitting code here

            })
        );
    })

Or you could reject the promise chain from the first .then method call, using

.then(() => {
    // some code
    return Promise.reject(new Error('fail'))
})
ZabdiAG
  • 155
  • 2
  • 5
  • Note that `snapshot` is not an Array (even in the first `then()`). You need to call it’s `docs` property to get an array. – Renaud Tarnec Apr 02 '20 at 18:12