0

I'm struggling a bit with Promise and async/await, i was sure i understood enough but i'm facing an issue that i don't understand. We are inside a discord bot command algorithm. This command can be executed for the user himself if no argument given, or for another user. The another user way requires to find it, by looking for it by nick/username or if it is a mention fetch it directly. But when it is about a mention, the operations execute in disorder and make the command fail.

I tried different ways, moving or framing the code parts, also surrounded the fetchMember call in an another async function and await inside on the fetchMember, but still the same result.

let targetMember;
const findTargetMember = (msg, targetArg) => {
    return new Promise((resolve, reject) => {
        if( msg.mentions.users.size>0 )
        {
            console.log("there are user mentions, taking the first one to get member", msg.mentions.users.first());
            msg.guild.fetchMember(msg.mentions.users.first()).then(member => {
                console.log("found member, resolving", member);
                return resolve(member);
            });
        }
        else
        {
            msg.guild.members.find(member => {
                if( member.nickname && member.nickname.toLowerCase()===targetArg.toLowerCase() )
                {
                    return resolve(member);
                }
                else if( member.user.username.toLowerCase()===targetArg.toLowerCase() )
                {
                    return resolve(member);
                }
            });
        }
        return resolve(null);
    });
};

(async () => {
    targetMember = msg.member;
    if( args[0] )
    {
        console.log("looking for another target member");
        targetMember = await findTargetMember(msg, args[0]);
        console.log("target member result :" + targetMember);
    }
    if( !targetMember )
    {
        return Replier.say(msg.channel, "Invalid member argument given", [msg.author]);
    }
})();
console.log( targetMember );

The result in console is :

looking for another target member
there are user mentions, taking the first one to get member User {}
GuildMember {}
found member, resolving GuildMember {}
target member result : null

What i expected :

looking for another target member
there are user mentions, taking the first one to get member User {}
found member, resolving GuildMember {}
target member result : GuildMember {}
GuildMember {}

I would like to understand what i did wrong and missed.

EDIT : Tried it without async/await since it was said the problem came from that, so here another code version :

const findAnotherTargetMember = (msg, targetArg) => {
    return new Promise((resolve, reject) => {
        console.log("trying to find a target from an argument");
        if( msg.mentions.users.size>0 )
        {
            console.log("there are user mentions, taking the first one", msg.mentions.users.first());
            msg.guild.fetchMember(msg.mentions.users.first()).then(member => {
                console.log("got member from it, resolving", member);
                return resolve(member);
            });
        }
        else
        {
            console.log("no user mentions, search by nick/username in guild members");
            msg.guild.members.find(member => {
                if( member.nickname && member.nickname.toLowerCase()===targetArg.toLowerCase() )
                {
                    console.log("found by nickname, resolving", member);
                    return resolve(member);
                }
                else if( member.user.username.toLowerCase()===targetArg.toLowerCase() )
                {
                    console.log("found by username, resolving", member);
                    return resolve(member);
                }
            });
        }
        console.log("no valid target found, resolving", null);
        return resolve(null);
    });
};

const defineTargetMember = (msg, args) => {
    return new Promise((resolve, reject) => {
        console.log("defining target");
        let targetMember = msg.member;
        console.log("set to message sender by default", targetMember);
        if( args[0] )
        {
            console.log("argument found, trying to use it for get another target");
            findAnotherTargetMember(msg, args[0]).then(anotherTargetMember => {
                console.log("what came with this argument", anotherTargetMember);
                if( anotherTargetMember===null )
                {
                    Replier.say(msg.channel, "Invalid member argument given", [msg.author]);
                }
                console.log("resolving 2", anotherTargetMember);
                return resolve(anotherTargetMember);
            });
        }
        console.log("resolving 1", targetMember);
        return resolve(targetMember);
    });
};

defineTargetMember(msg, args).then(targetMember => {
    if( targetMember!==null )
    {
       // .... code here
    }
});

So there is no more problem with async variable value assign. Console output :

defining target
set to message sender by default GuildMember {}
argument found, trying to use it for get another target
trying to find a target from an argument
there are user mentions, taking the first one User {}
no valid target found, resolving null
resolving 1 GuildMember {}
got member from it, resolving GuildMember {}
what came with this argument null
resolving 2 null

What was expected :

defining target
set to message sender by default GuildMember {}
argument found, trying to use it for get another target
trying to find a target from an argument
there are user mentions, taking the first one User {}
got member from it, resolving GuildMember {}
resolving 1 GuildMember {}
what came with this argument GuildMember {}

I'm totally lost..

Flozza
  • 131
  • 2
  • 12
  • Possible duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – CertainPerformance Jul 27 '19 at 11:24
  • The lines below the `async` IIFE run synchronously, before the IIFE has finished, if the IIFE contains any `await`s – CertainPerformance Jul 27 '19 at 11:25
  • @CertainPerformance i removed all async/await things from the code and used only promise. Still not good (see edited post) – Flozza Jul 27 '19 at 12:53
  • Your `return resolve(null);` is running synchronously inside the Promise constructor, so it always resolves immediately with nothing, remove that line (and better to `reject` in case of errors, in an `else` inside the `guild.fn` callback) – CertainPerformance Jul 27 '19 at 12:57
  • Ok i got it... The concept is really difficult to understand. Thanks you – Flozza Jul 27 '19 at 13:43

2 Answers2

0

Your buildMember is being printed bafore because the async block, if you need all code to execute in order you must use a away method our pass log as callback function(dont do that). The easy way is put your code on response of promise.

Rodrigo Sene
  • 309
  • 1
  • 13
  • but i tried to put the whole code in an async function and call the nested async with an await in front of and the result is exactly the same – Flozza Jul 27 '19 at 12:29
0

I finally got the code working this way :

    const findAnotherTargetMember = (msg, targetArg) => {
        return new Promise((resolve, reject) => {
            if( msg.mentions.users.size>0 )
            {
                msg.guild.fetchMember(msg.mentions.users.first()).then(member => {
                    return resolve(member);
                });
            }
            else
            {
                msg.guild.members.find(member => {
                    if( member.nickname && member.nickname.toLowerCase()===targetArg.toLowerCase() )
                    {
                        return resolve(member);
                    }
                    else if( member.user.username.toLowerCase()===targetArg.toLowerCase() )
                    {
                        return resolve(member);
                    }
                });
            }
        });
    };

    const defineTargetMember = (msg, args) => {
        return new Promise((resolve, reject) => {
            let targetMember = msg.member;
            if( args[0] )
            {
                findAnotherTargetMember(msg, args[0]).then(anotherTargetMember => {
                    if( anotherTargetMember===null )
                    {
                        Replier.say(msg.channel, "Invalid member argument given", [msg.author]);
                    }
                    return resolve(anotherTargetMember);
                });
            }
            else
            {
                resolve(targetMember);
            }
        });
    };

    defineTargetMember(msg, args).then(targetMember => {
        if( targetMember!==null )
        {
            // code here...
        }
    });
Flozza
  • 131
  • 2
  • 12