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

This code doesn't seem to fire in order?

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

此代码适用于我正在创建的 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;

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



    I am ready!
    string + 
    2
    3
    1

这表明代码运行宁按了我预期的错误顺序。

非常感谢所有帮助:)

*更新!非常感谢大家理解为什么它不起作用。我在 vidid = youtubetest.respond(query, msg) 的主文件中找到了一个解决方案,当它这样做时,直到函数完成后才分配变量它在没有变量的情况下进入我的其余代码。为了解决这个问题,我简单地放置了一个 if 语句来检查变量是否未定义并等待它被定义。*

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

回调函数只是在特定事件上调用:

  • 当有数据需要处理时
  • 出错
  • 在您的情况下,例如当 youtube 搜索结果准备就绪时, 'ready' 收到事件或 'message' 收到。
  • 等等

就像之前提到的,javascript 中的很多东西都是异步运行的,因此有回调处理程序。它以异步方式运行的原因是为了避免您的其余代码被远程调用"blocked"。为了避免陷入回调地狱,我们大多数 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);
        })
    };

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

这承诺 returns vidid,因此您将设置 vidid = youtubetest.response(query, msg);,并且每当该函数被调用时,您都会:

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

Javascript 设计为异步运行,并试图破解你的方式,让你快速进入黑暗的地方。据我所知,您还以 nodeJS 为目标,这意味着一旦您同步启动 运行 某些内容,您就会降低其他用户的性能,因为每个人都必须等待该同步调用完成。

一些建议阅读:

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