解决并发ajax调用限制的最佳实践

时间:2018-10-26 10:37:02

标签: javascript ajax angular typescript asynchronous

冒着因未发布代码而被烤的风险,解决ajax请求的6个并发调用限制的最佳方法是什么?

因此,当前我正在使用的应用程序在页面加载时最多可以有40个左右的ajax请求。对于背景,大多数这些请求是针对隐藏在选项卡后面的各种图形。用户可以触发一些请求(例如,在不刷新页面的情况下更新实体名称)。这意味着,由于并发请求受到限制,用户只有在运行其他5个请求后才能更改任何内容,这是不可接受的用户体验。

这可能意味着该应用程序的结构不良,但是大多数内容并不需要立即加载。

无论如何,我对fetch()和Webworkers进行了一些研究,但是找不到有关这些内容是否有助于克服限制的任何信息。

一种解决方案是将资源放在不同的子域中,但这会使后端API变得不必要地复杂(这是浏览器问题,而不是服务器问题)。

我已经考虑过以下方法:

  • 延迟请求,直到用户积极需要它们为止(IMO,这是糟糕的用户体验,因为他们将不得不等待很多时间,这很烦人)
  • 创建一个排队系统,为用户发起的请求留出一个空白(我不确定如何实现,但是应该可行)
  • 重组API,以便每个请求返回更多数据(这再次是主要后端处理,感觉有点肮脏和不稳定。这也不一定会缩短加载时间)
  • 将呼叫与Multiple Async AJAX Calls Best Practice链接在一起(但是,鉴于不相关端点上的呼叫数量无法预测,因此我认为这在这里并不实用)
  • 网络工作者? (再次,不确定这是否有帮助,因为它用于多线程js)
  • fetch()? (我找不到有关是否受相同限制的信息)

3 个答案:

答案 0 :(得分:1)

这是非常基于意见的。

40个请求并非没有道理,但是取决于您的服务器和站点设置,它可能需要一段时间。

有了这么多电话,我会将其中一些电话捆绑成一个initializePage=X电话。这确实涉及服务器端的一些工作。

Delay requests不一定很糟糕,具体取决于您预计的交付时间。如果可能的话,您可以呈现某种动画或“预期结果”,直到响应滴答滴答为止,以使用户感到满意。 Queing的请求也是如此。

如果在服务器上运行大量初始化操作(例如安全检查),则重组代码以返回捆绑中的所有内容也可以极大地加快站点的速度。

如果仍然需要性能,则可以研究提供更快结果的连接,例如EventSourceWebSocket。这种更快的连接还允许使用更灵活的链接方法。例如,EventSource支持事件,因此您可以在一个捆绑请求中设置多个事件,并在服务器返回数据时将其触发。

Webworkers并不是答案,因为这里的问题是连接速度和并发连接限制。

答案 1 :(得分:1)

我认为我们不能直接回答这个问题。您提到的几种解决方案是可行的,但根据工作水平而有所不同。如果您愿意调整体系结构,可以考虑使用GraphQL方法来为您打包捆绑软件。我还要说的是,您可以维护REST,但是有一个特殊的代理服务可以为您捆绑数据。我还要说,不要让RESTfullness支配或强迫您发展。

在我看来,将请求延迟到用户需要之前,这似乎是适当的选择。这就是为什么我们要“超越折叠” CSS样式和无限滚动的基础。首先先加载所需的内容,然后在需要的时候推迟可能实际上无关紧要的内容。

答案 2 :(得分:1)

如果从一个线程中调用这些请求,则AJAX调用的并发性将会显现出来。如果将WebWorker与AJAX一起使用,则完全没有问题,原因是Webworker的每个实例都将被隔离在一个不在主线程中的线程中。

我称其为JaxWeb,我将在下周推出git repo,在那里您可能会找到处理该问题的纯JS代码。目前正在测试中,但是是的,确实可以解决问题。

示例:

在JaxWeb.js中添加以下代码

onmessage = function (e) {
    var JaxWeb = function (e) {
        return {
            requestChannel: {},
            get_csrf_token: function () {
                return this._csrf_token;
            },
            set_csrf_token: function (_csrf_token = null) {
                this._csrf_token = _csrf_token;
            },
            prepare: (function ( e ) {
                this.requestChannel = new XMLHttpRequest();
                this.requestChannel.onreadystatechange = function () {
                    if (this.readyState == 4 && this.status == 200) {
                        postMessage(JSON.parse(this.responseText));
                    }
                };
                this.requestChannel.open(e.data.method, e.data.callname, true);
                this.requestChannel.setRequestHeader("X-CSRF-TOKEN", e.data.token);
                var postData = '';
                if (e.data.data)
                    postData = JSON.stringify(e.data.data);
                this.requestChannel.send(postData);
            })(e)
        }
    };
    return JaxWeb(e);
}

用法:

jaxWebGetServerResponse = function () {
    var wk2 = new Worker('path_to_jaxweb_js/JaxWeb.js');

    wk2.postMessage({
        "callname": '<url end point>',
        "method": '<your http method>',
        "data": ''
    });

    wk2.onmessage = function (serverResponse) {
        //
        //process results
        //with data that is received from server
    }
};



//Invoke the function 
jaxWebGetServerResponse();