【问题标题】:How to execute synchronous HTTP requests in JavaScript如何在 JavaScript 中执行同步 HTTP 请求
【发布时间】:2021-04-27 09:56:56
【问题描述】:

我需要在 node.js 程序中执行未知数量的 http 请求,并且它需要同步发生。只有当一个人得到响应时,下一个请求才会被执行。如何在 JS 中实现它?

我用requset包同步试过了:

function HttpHandler(url){

  request(url, function (error, response, body) {
     ...
  })

}

HttpHandler("address-1")
HttpHandler("address-2")
...
HttpHandler("address-100")

并与 request-promise 异步:

async function HttpHandler(url){

  const res = await request(url)
  ...

}

HttpHandler("address-1")
HttpHandler("address-2")
...
HttpHandler("address-100")

它们都不起作用。正如我所说,我可以通过程序获得未知数量的 http 请求,这取决于最终用户。

有什么解决办法吗?

【问题讨论】:

  • nodejs中没有同步http请求这种东西(nodejs中的所有网络都是异步的)。您的意思是说您需要一个接一个地按顺序运行它们,即使它们是异步的?并且,请说明您要如何处理这些多次调用的响应,因为这将影响代码的编写方式。目前,它们似乎并不相互依赖,因此它们可以并行运行,而无需按照严格的顺序对其进行排序。
  • 另外,request() 包已被弃用,不推荐用于新代码。您可以从替代列表中选择here。我最喜欢的是got(),它还可以通过使用promises 和await 更轻松地对您的调用进行排序。
  • 请不要尝试
  • @jfriend00 http 请求可以是异步的,我很好。我只需要程序是同步的。例如,当一个http得到响应然后发送下一个时得到通知,我想我可以使用某种形式的回调,但我不知道如何实现它,因为我没有所有的列表运行前的请求。它将是完全动态的。
  • 请展示您问题的真实逻辑,以便我们为问题提供完整的解决方案。

标签: javascript node.js http asynchronous async-await


【解决方案1】:

使用got() 库,而不是request() 库,因为request() 库已被弃用并且不支持承诺。然后,您可以使用async/awaitfor 循环依次对您的调用进行排序。

const got = require('got');
let urls = [...];    // some array of urls

async function processUrls(list) {
    for (let url of urls) {
        await got(url);
    }
}

processUrls(urls).then(() => {
    console.log("all done");
}).catch(err => {
    console.log(err);
});

您正在声明某种 URL 的动态列表,但不会显示它是如何工作的,因此您必须自己弄清楚这部分逻辑。我很乐意展示如何解决这部分问题,但您还没有告诉我们应该如何工作。


如果您想要一个可以定期添加项目的队列,您可以执行以下操作:

class sequencedQueue {
    // fn is a function to call on each item in the queue
    // if its asynchronous, it should return a promise
    constructor(fn) {
        this.queue = [];
        this.processing = false;
        this.fn = fn;
    }
    add(...items) {
        this.queue.push(...items);
        return this.run();
    }
    async run() {
        // if not already processing, start processing
        // because of await, this is not a blocking while loop
        while (!this.processing && this.queue.length) {
            try {
                this.processing = true;
                await this.fn(this.queue.shift());
            } catch (e) {
                // need to decide what to do upon error
                // this is currently coded to just log the error and
                // keep processing.  To end processing, throw an error here.
                console.log(e);
            } finally {
                this.processing = false;
            }
        }
    }
}

【讨论】:

  • 我还推荐node-fetch,因为它与浏览器中使用的 Fetch API 兼容,并且使可移植性更容易一些。
  • @Brad - 这里使用哪个 API 是一个见仁见智的问题。对于在 nodejs 中编程,fetch() API 在许多不同的方面(流、解析响应、一般功能支持等)远不如got() 方便。当然,如果您想与浏览器编程兼容,请使用 node-fetch,但如果不是,我认为这不是最佳选择。
  • 这将完美运行。但还有一件事。一直有新的请求要发送。而且我知道可以将它们推送到一个数组并每隔 X 秒运行一次,但我希望找到更好的方法。
  • @dev3dev - 正如我多次说过的那样,如果您展示更多关于新网址如何到达的信息,我可以为此提供解决方案,但不能为我不知道的东西编写代码关于。如果它是一个连续的过程,您可以使用队列而不是数组(类似的概念)。或者在您拥有的所有 URL 上运行此命令,并将任何新到达的 url 放入一个新数组中。当这个数组完成后,开始处理新到达的数组。有数百种方法可以进行某种排队。您可以在队列上使用 while 循环。 while (queue not empty) { await got(next queue item) }
  • @jfriend00 谢谢。但是如果我的例子是正确的,那么如果队列将变为空一次,while 循环将停止,并且将不会处理将插入队列的新 URL,不是吗?这就是为什么我考虑设置计时器以每隔几秒检查一次数组/队列中的新 URL,但我觉得这不是正确的解决方案。很抱歉没有显示完整的代码,这是 10 个项目文件,我试图让问题尽可能简单。
猜你喜欢
  • 2018-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-04
  • 1970-01-01
  • 2011-10-04
相关资源
最近更新 更多