Kautilya Kondragunta
Kautilya Kondragunta

Reputation: 155

Javascript filter method returning the original array even when returned false

I have a filter method as follows:

    let newArray = Alerts[symbol].filter(async (alert: IDiscordSymbolAlert, alert_index: number) => {
        // If Price when set is greater than alert price, price has to move UP to trigger
        if (alert.price_when_set < alert.alert_price) {
            hasToGo = Change.UP;
        } 
        // If Price when set is greater than alert price, price has to move DOWN to trigger
        else if (alert.price_when_set > alert.alert_price){
            hasToGo = Change.DOWN;
        }

        /**If the hasToGo is UP and current price is greater than alert price, then ALERT USER [OR]
        // If the hasToGo is DOWN and current price is lesser than alert price, then ALERT USER **/ 
        if((hasToGo === Change.UP && (price >= alert.alert_price)) ||
        (hasToGo === Change.DOWN && (price <= alert.alert_price))) {
            /**
             * Send Notification that alert has been hit
             */
            let userToSend = await discord.users.fetch(alert.userID)
            if(!userToSend) return;
            //@ts-ignore
            userToSend.send(`> @everyone\n\n${symbol} has reached your alert price - ${alert.alert_price}`);
            // remove that alert
            guild_modified = true;
            return false;
        }

        return true;
    });


    // When logged here, it shows the entire array even though certain values have returned false.
    // I know they returned false because the block in which they returned false was executed and 
     //i did receive a notification which was executed in the same block.

    console.log(newArray);

When logged here (console.log), it shows the entire array even though certain values have returned false. I know they returned false because the block in which they returned false was executed and i did receive a notification which was executed in the same block. I know this has something to do with the async/await, but i'm not exactly sure what. Can someone please take a look.

updated question

Alerts[symbol].forEach(async (alert: IDiscordSymbolAlert, alert_index: number) => {
        // If Price when set is greater than alert price, price has to move UP to trigger
        if (alert.price_when_set < alert.alert_price) {
            hasToGo = Change.UP;
        } 
        // If Price when set is greater than alert price, price has to move DOWN to trigger
        else if (alert.price_when_set > alert.alert_price){
            hasToGo = Change.DOWN;
        }

        /**If the hasToGo is UP and current price is greater than alert price, then ALERT USER [OR]
        // If the hasToGo is DOWN and current price is lesser than alert price, then ALERT USER **/ 
        if((hasToGo === Change.UP && (price >= alert.alert_price)) ||
        (hasToGo === Change.DOWN && (price <= alert.alert_price))) {
            /**
             * Send Notification that alert has been hit
             */
            let userToSend = await discord.users.fetch(alert.userID)
            if(!userToSend) return;
            //@ts-ignore
            userToSend.send(`> @everyone\n\n${symbol} has reached your alert price - ${alert.alert_price}`);
            // remove that alert
            Alerts![symbol].splice(alert_index, 1);
            guild_modified = true;
        }
    });

    console.log(Alerts[symbol]);

Since filter cannot be used in this case with async/await. This is me using forEach() loop and manually deleting the matched object in the array using splice(). But since the forEach itself is asynchronous and the console.log is acting outside the async block. It's not returning the new array, rather the unmodified one. How can i return the new array to be used outside the scope of the forEach block.

Thanks in advance!

Upvotes: 0

Views: 522

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074138

You can't use an async function with filter. filter returns all elements for which the callback returns a truthy value. async functions always return promises, which are objects, and all non-null objects are truthy.

If your filter check needs to be async, your entire operation is async and needs to be handled as such.

Here's an off-the-cuff async filtering function that does the element checks in parallel. Again, like all async functions, it returns a promise of its result:

async function filterAsync(array, callback, thisArg = undefined) {
    const flags = await Promise.all(array.map(callback, thisArg));
    const result = [];
    for (let n = 0; n < array.length; ++n) {
        if (flags[n]) {
            result.push(array[n]);
        }
    }
    return result;
}

To use that, you have to consume the promise:

// In an `async` function (assuming you want errors to propagate):
const newArray = await filterAsync(Alerts[symbol], element => /*...keep-or-toss logic...*/);
// ...use `newArray`...

or

// Not in an `async` function
filterAsync(Alerts[symbol], element => /*...keep-or-toss logic...*/)
.then(newArray => {
    // ...use `newArray`...
})
.catch(error => {
    // ...handle/report error...
});

Upvotes: 7

Related Questions