这段代码似乎没有按顺序触发?

Posted

技术标签:

【中文标题】这段代码似乎没有按顺序触发?【英文标题】:This code doesn't seem to fire in order? 【发布时间】:2017-04-23 11:25:07 【问题描述】:

我的问题是代码似乎没有按顺序运行,如下所示。

此代码适用于我正在创建的 discord.js 机器人。



    var Discord = require("discord.js");
    var bot = new Discord.Client();
    var yt = require("C:/Users/username/Documents/Coding/Discord/youtubetest.js");
    var youtubetest = new yt();
    var fs = require('fs');
    var youtubedl = require('youtube-dl');
    var prefix = "!";
    var vidid;
    var commands = 
      play: 
       name: "!play ",
       fnc: "Gets a Youtube video matching given tags.",
       process: function(msg, query) 
         youtubetest.respond(query, msg);
         var vidid = youtubetest.vidid;
         console.log(typeof(vidid) + " + " + vidid);
         console.log("3");
       
     
    ;

    bot.on('ready', () => 
      console.log('I am ready!');
    );

    bot.on("message", msg => 
      if(!msg.content.startsWith(prefix) || msg.author.bot || (msg.author.id === bot.user.id)) return;

      var cmdraw = msg.content.split(" ")[0].substring(1).toLowerCase();
      var query = msg.content.split("!")[1];
      var cmd = commands[cmdraw];
      if (cmd) 
        var res = cmd.process(msg, query, bot);
        if (res) 
          msg.channel.sendMessage(res);
        
       else 
        let msgs = [];
        msgs.push(msg.content + " is not a valid command.");
        msgs.push(" ");
        msgs.push("Available commands:");
        msgs.push(" ");
        msg.channel.sendMessage(msgs);
        msg.channel.sendMessage(commands.help.process(msg));
      
    );

    bot.on('error', e =>  console.error(e); );
    bot.login("mytoken");

youtubetest.js 文件:



    var youtube_node = require('youtube-node');
    var ConfigFile = require("C:/Users/username/Documents/Coding/Discord/json_config.json");
    var mybot = require("C:/Users/username/Documents/Coding/Discord/mybot.js");

    function myyt () 
        this.youtube = new youtube_node();
        this.youtube.setKey(ConfigFile.youtube_api_key);
        this.vidid = "";
    

    myyt.prototype.respond = function(query, msg) 
      this.youtube.search(query, 1, function(error, result) 
        if (error) 
          msg.channel.sendMessage("There was an error finding requested video.");
         else 
          vidid = 'http://www.youtube.com/watch?v=' + result.items[0].id.videoId;
          myyt.vidid = vidid;
          console.log("1");
        
      );
      console.log("2");
    ;

    module.exports = myyt;

正如代码所示,我有一个机器人能够处理的命令的对象,并且我有一个函数可以在收到消息时运行所述命令。 在整个代码中,您可以看到我放置了三个带有 1、2 和 3 的 console.log,显示了我希望代码部分运行的顺序。当代码运行并找到查询时,输出是这样的:



    I am ready!
    string + 
    2
    3
    1

这表明代码以错误的顺序运行。

非常感谢所有帮助:)

*更新!非常感谢大家理解为什么它不起作用。我找到了一个解决方案,在 vidid = youtubetest.respond(query, msg) 的主文件中,在函数完成之前不会分配变量,因此它会进入我的代码的其余部分没有变量。为了解决这个问题,我只需放置一个 if 语句检查变量是否未定义并等待它被定义。*

【问题讨论】:

您正在编写异步代码。 console.log 2 在异步函数之外。我不确定你会发生什么。 对不起,我还没有做过很多类似的事情,我还是个青少年,还在学习 javascript。你到底是什么意思异步,哪些部分是和不是? this.youtube.search 可能是一个异步函数,这意味着它在后台执行某些操作,而函数的 callback 之外的其他代码继续执行。所以你的function(error, result) ... 是只在搜索操作完成后执行 的回调。因此console.log(2)自然会在回调之前被调用。 但是第一个文件中的console.log(3)是先运行的,所以函数youtubetest.respond(query, msg)不应该在console.log(3)之前运行吗? youtubetest.respond 可能也是异步的。 【参考方案1】:

就像之前提到的,javascript 中的很多东西都是异步运行的,因此需要回调处理程序。它以异步方式运行的原因是为了避免您的其余代码被远程调用“阻塞”。为了避免陷入回调地狱,我们大多数 Javascript 开发人员越来越多地转向Promises。所以你的代码可能看起来更像这样:

   myyt.prototype.respond = function(query, msg) 
        return new Promise(function(resolve, reject) 
            this.youtube.search(query, 1, function(error, result) 
                if (error) 
                    reject("There was an error finding requested video."); // passed down to the ".catch" statement below

                 else 
                    vidid = 'http://www.youtube.com/watch?v=' + result.items[0].id.videoId;
                    myyt.vidid = vidid;
                    console.log("1");
                    resolve(2); // Resolve marks the promises as successfully completed, and passes along to the ".then" method
                
            );
        ).then(function(two) 
            // video is now the same as myyt.vidid as above. 
            console.log(two);
        ).catch(function(err) 
            // err contains the error object from above
            msg.channel.sendMessage(err);
        )
    ;

这自然需要对使用此过程的任何事物进行更改,但是创建自己的原型似乎……很奇怪。

此承诺返回 vidid,因此您需要设置 vidid = youtubetest.response(query, msg);,并且每当调用该函数时,您都会这样做:

vidid.then(function(id) 
 // id is now the vidid.
);

Javascript 在设计上是异步运行的,并且试图破解你的方式会导致你快速进入黑暗的地方。据我所知,您也是针对 nodeJS 的,这意味着一旦您开始同步运行某些东西,就会影响其他用户的性能,因为每个人都必须等待同步调用完成。

一些建议阅读:

http://callbackhell.com/ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise https://***.com/a/11233849/3646975

我还建议查找 ES6 语法,因为它可以缩短您的代码并使您的生活更轻松(原生 promise 仅在 ES6 中引入,NodeJS 4 及更高版本支持(或多或少))

【讨论】:

谢谢,这确实有助于解释我的问题,虽然我意识到问题是错误的,但它仍然对我有很大帮助。非常感谢! :)【参考方案2】:

在 javascript 中,请记住,您传递给其他函数的任何回调函数都是异步调用的。 IE。对回调函数的调用可能不会“按顺序”发生。在这种情况下,“按顺序”表示它们在源文件中出现的顺序。

回调函数只是在某个事件上调用:

当有数据需要处理时 出错 在您的情况下,例如当 youtube 搜索结果准备好时, 接收到“就绪”事件或接收到“消息”。 等

【讨论】:

嗯,好的,但是如何将变量 vidid 与 youtube 搜索的结果一起返回到 mybot.js。我应该在问题中更好地说明。 那是另一个问题。 :-) 在您的播放功能中,从 vidid 变量的开头删除“var”,然后您就不会覆盖上面几行的 vidid 变量。 然后在代码的其他地方检查是否 vidid !== undefined 并使用它。 我接受了你的建议,但它并没有改变结果。输出仍然是string + 谢谢@teroi。我更新了上面的文字以显示我修复它的方式。

以上是关于这段代码似乎没有按顺序触发?的主要内容,如果未能解决你的问题,请参考以下文章

对于每个不按正确顺序开火

即使没有进入无限循环,这段代码似乎也永远无法解决

Firebase 查询未按调用顺序触发

有人能告诉我为啥这段代码似乎可以工作,但不能……拜托?

无法按顺序触发两个 jQuery ajax 调用

这段代码是关于选择排序的,但是当我运行代码时它没有按预期工作