繁体   English   中英

DiscordJS - 异步响应消息

[英]DiscordJS - asynchronously respond to messages

我正在编写的 discord 机器人中的命令之一涉及使用 JSDom 抓取网站,等待其脚本全部运行,然后再读取 HTML。 我发现有时该站点的脚本需要很长时间才能运行,这会导致机器人在等待最后一个查询完成时无响应 3 分钟。 如何将抓取操作变成异步 function,以便机器人在等待第一次调用完成时仍然可以响应其他消息?

这是我当前代码的简化版本:

client.on('message', message => {
    // command1 - the web scraper
    console.log("benchmark A");
    jsdom.JSDOM.fromURL(link, {resources: "usable", runScripts: "dangerously"}).then(dom => {
        console.log("benchmark B");
        dom.window.document.addEventListener('DOMContentLoaded', () => {
            console.log("benchmark C");
            setImmediate(() => {
                console.log("benchmark D");
                // read the DOM and do stuff with it
                message.channel.send(some_value_from_dom);
            });
        });

    });
    // command2
    // command3
    // command4
    // etc.
});

你可以看到我包含了一些日志语句。 当有人调用command1时,控制台中发生的情况是基准测试 A、B、C 几乎立即显示,但随后基准测试 D 最多需要 3 分钟才会出现。 我遇到的主要问题是,在基准 C 和基准 D 之间的那段时间里,没有其他人可以查询我的机器人。 所以我想以某种方式将代码的网络抓取部分移动到它自己的异步 function 中,这样它就可以在后台运行而不阻塞主块,从而让其他人在处理这个耗时的命令时继续使用机器人. 但我不知道如何 go 关于在 NodeJS 中执行此操作,因为 JavaScript 不支持多线程。

多一点挖掘,我已经解决了我自己的问题。 我将网络抓取 function 放入一个工作线程中,每次我想运行它时,我都会将链接从主线程发布到工作线程,让它做它的事情,然后当它完成后将消息发布回主线程。

这是之前的代码:

// bot.js

client.on('message', message => {
    jsdom.JSDOM.fromURL(link, {resources: "usable", runScripts: "dangerously"}).then(dom => {
        dom.window.document.addEventListener('DOMContentLoaded', () => {
            setImmediate(() => {
                // read the DOM and do stuff with it
                message.channel.send(some_value_from_dom);
            });
        });

    });
});

这是它之后的样子:

// bot.js

const worker = new Worker('./worker.js');

client.on('message', message => {
    // Construct link
    worker.once('message', response => {
        message.channel.send(response);
    });
    worker.postMessage(link);
});

// worker.js

parentPort.on('message', link => {
    jsdom.JSDOM.fromURL(link, {resources: "usable", runScripts: "dangerously"}).then(dom => {
        dom.window.document.addEventListener('DOMContentLoaded', () => {
            setImmediate(() => {
                // read the DOM and do stuff with it
                parentPort.post(some_value_from_dom);
            });
        });
    });
});

现在所有的网络抓取都是单独完成的,其他用户仍然可以同时查询机器人的其他命令,而无需等待几分钟来完成第一个任务。 也许我错过了一个更简单的解决方案,但是 a) 我不会声称自己是 JS 专家,并且 b) 这完全按照我想要的方式工作,所以我认为没有理由再次更改它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM