获取成员的预期同步代码不同步

Posted

技术标签:

【中文标题】获取成员的预期同步代码不同步【英文标题】:Expected synchronous code to fetch member not synchrone 【发布时间】:2019-12-05 11:35:36 【问题描述】:

我在 Promise 和 async/await 方面有点挣扎,我确信我理解的足够多,但我正面临一个我不理解的问题。 我们在一个不和谐的机器人命令算法中。如果没有给出参数,则可以为用户自己执行此命令,也可以为其他用户执行此命令。另一种用户方式需要通过昵称/用户名查找它,或者如果它是提及直接获取它。但是在提到的时候,操作就会乱七八糟,导致命令失败。

我尝试了不同的方法,移动或构建代码部分,还在另一个异步函数中包围了 fetchMember 调用,并在 fetchMember 内部等待,但结果仍然相同。

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

控制台的结果是:

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

我的预期:

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 

我想了解我做错了什么,错过了什么。

编辑:在没有 async/await 的情况下进行了尝试,因为据说问题来自于此,所以这里有另一个代码版本:

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

所以异步变量赋值不再有问题。 控制台输出:

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

预期结果:

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 

我完全迷路了..

【问题讨论】:

Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference的可能重复 asyncIIFE 下面的行同步运行,在 IIFE 完成之前,如果 IIFE 包含任何awaits @CertainPerformance 我从代码中删除了所有异步/等待的东西,只使用了承诺。仍然不好(见编辑后的帖子) 你的 return resolve(null); 在 Promise 构造函数中同步运行,所以它总是立即解决,删除该行(最好是 reject 以防出错,在 elseguild.fn回调) 好吧,我明白了……这个概念真的很难理解。谢谢你 【参考方案1】:

我终于让代码以这种方式工作了:

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

【讨论】:

【参考方案2】:

由于异步块,您的 buildMember 正在被打印,如果您需要执行所有代码以便您必须使用我们的传递日志作为回调函数的离开方法(不要这样做)。 简单的方法是将您的代码放在承诺的响应上。

【讨论】:

但我尝试将整个代码放在异步函数中,并在前面调用嵌套异步,结果完全一样

以上是关于获取成员的预期同步代码不同步的主要内容,如果未能解决你的问题,请参考以下文章

面试官必问java 并发知识总结-同步与锁

同步线程在不同类中执行代码的有效方法?

next-redux-wrapper 服务器不与客户端同步?

浅谈Java三种实现线程同步的方法

浅谈Java三种实现线程同步的方法

线程安全和线程同步的理解