最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 改善应用程序性能和代码质量:通过代理模式组合HTTP请求

    正文概述 掘金(杭州程序员张张)   2021-03-15   473

    在前端项目中,我们的网页通常需要向服务器发送多个HTTP请求。

    假设我们的产品具有一项功能,即每当用户单击 li 标记时,客户端都会向服务器发送一个HTTP请求。

    这是一个简单的Demo:

    <html>
    
    <body>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
        </ul>
    
        <script>
            // Suppose this function is used to make HTTP requests to the server
            var sendHTTPRequest = function(message) {
                console.log('Start sending HTTP message to the server: ', message)
                console.log('1000ms passed')
                console.log('HTTP Request is completed')
            }
    
            var ul = document.getElementsByTagName('ul')[0];
    
            ul.onclick = function(event) {
                if (event.target.nodeName === "LI") {
    
                    // Executes this function every time the <li> tag is clicked.
                    sendHTTPRequest(event.target.innerText)
                }
            }
        </script>
    </body>
    
    </html>
    

    在上面的代码中,我们直接使用简单的 sendHTTPRequest 函数来模拟发送HTTP请求。这样做是为了更好地专注于核心目标,因此我简化了一些代码。

    然后,我们将click事件绑定到 ul 元素。每次用户单击诸如 <li> 5 </li> 之类的标记时,客户端将执行 sendHTTPRequest 函数以向服务器发出HTTP请求。

    上面的程序是这样的:

    改善应用程序性能和代码质量:通过代理模式组合HTTP请求

    为了使你们更容易尝试,我制作了一个Codepen演示:codepen.io/bitfishxyz/…

    当然,在真实的项目中,我们可能会向服务器发送一个文件,推送通知,或者发送一些日志。但为了演示的惯例,我们将跳过这些细节。

    好了,这是一个很简单的演示,那么上面的代码有没有什么缺点呢?


    如果您的项目非常简单,那么编写这样的代码应该没有问题。但是,如果您的项目很复杂,并且客户端需要频繁向服务器发送HTTP请求,则此代码效率很低。

    在上面的示例中,如果任何用户反复快速单击 li 元素会发生什么?这时,我们的客户端需要向服务器发出频繁的HTTP请求,并且每个请求都会消耗大量时间和服务器资源。

    客户端每次与服务器建立新的HTTP连接时,都会消耗一些时间和服务器资源。因此,在HTTP传输机制中,一次传输所有文件比多次传输少量文件更为有效。

    例如,您可能需要发送五个HTTP请求,每个HTTP请求的HTTP数据包大小为1MB。现在,您一次发送一个HTTP请求,数据包大小为5MB。通常预期后者的性能要比前一个更好。

    网页上的大量HTTP请求可能会减慢网页的加载时间,最终损害用户体验。如果加载速度不够快,这可能会导致访问者更快地离开该页面。

    因此,在这种情况下,我们可以考虑合并HTTP请求。

    在我们目前的项目中,我的思路是这样的:我们可以在本地设置一个缓存,然后在一定范围内收集所有需要发送给服务器的消息,然后一起发送。

    你可以暂停一下,自己试着想办法。

    提示:您需要创建一个本地缓存对象来收集需要发送的消息。然后,您需要使用定时器定时发送收集到的消息。

    这是一个实现。

    改善应用程序性能和代码质量:通过代理模式组合HTTP请求

    var messages = [];
    var timer;
    var sendHTTPRequest = function (message) {
      messages.push(message);
      if (timer) {
        return;
      }
      timer = setTimeout(function () {
        console.log("Start sending messages: ", messages.join(","));
        console.log("1000ms passed");
        console.log("HTTP Request is completed.");
    
        clearTimeout(timer);
        timer = null;
        messages = [];
      }, 2000);
    };
    

    每当客户端需要发送消息,也就是触发一个 onclick 事件的时候,sendHTTPRequest 并不会立即向服务器发送消息,而是先将消息缓存在消息中。然后,我们有一个计时器,该计时器在2秒钟后执行,并且在2秒钟后,该计时器会将所有先前缓存的消息发送到服务器。此更改达到了组合HTTP请求的目的。

    测试结果如下:

    改善应用程序性能和代码质量:通过代理模式组合HTTP请求

    如你所见,尽管我们多次触发点击事件,但在两秒钟内,我们只发送了一个HTTP请求。

    当然,为了方便演示,我将等待时间设置为2秒。如果你觉得这个等待时间太长,你可以缩短这个等待时间。

    对于不需要太多实时交互的项目,2秒的延迟并不是一个巨大的副作用,但它可以减轻服务器的很多压力。在适当的情况下,这是非常值得的。


    上面的代码确实为项目提供了一些性能改进。但是就代码设计而言,上面的代码并不好。

    第一,违反了单一责任原则。sendHTTPRequest 函数不仅向服务器发送HTTP请求,而且还组合HTTP请求。该函数执行过多操作,使代码看起来非常复杂。

    如果某个功能(或对象)承担了过多的责任,那么当我们的需求发生变化时,该功能通常将不得不发生重大变化。这样的设计不能有效地应对可能的更改,这是一个糟糕的设计。

    我们理想的代码如下所示:

    改善应用程序性能和代码质量:通过代理模式组合HTTP请求

    我们没有对 sendHTTPRequest 进行任何更改,而是选择为其提供代理。这个代理函数执行合并HTTP请求的任务,并将合并后的消息传递给 sendHTTPRequest 发送。然后我们以后就可以直接使用 proxySendHTTPRequest 方法了。

    您可以暂停片刻,然后尝试自己解决。

    这是一个实现:

    改善应用程序性能和代码质量:通过代理模式组合HTTP请求

    var proxySendHTTPRequest = (function() {
      var messages = [],
          timer;
      return function(message) {
        messages.push(message);
        if (timer) {
          return;
        }
        timer = setTimeout(function() {
          sendHTTPRequest(messages.join(","));
          clearTimeout(timer);
          timer = null;
          messages = [];
        }, 2000);
      };
    })();
    

    其基本思想与前面的代码类似,该代码使用 messages 变量在一定时间内缓存所有消息,然后通过计时器统一地发送它们。此外,这段代码使用了闭包技巧,将 messagestimer 变量放在局部作用域中,以避免污染全局名称空间。

    这段代码与前面的代码最大的区别是它没有更改 sendHTTPRequest 函数,而是将其隐藏在 proxySendHTTPRequest 后面。我们不再需要直接访问 sendHTTPRequest,而是使用代理 proxySendHTTPRequest 来访问它。proxySendHTTPRequestsendHTTPRequest 具有相同的参数列表和相同的返回值。

    这样的设计有什么好处?

    • 发送HTTP请求和合并HTTP请求的任务交给了两个不同的函数,每个函数专注于一个职责。它遵从单一责任原则,并使代码更容易理解。
    • 由于两个函数的参数是相同的,我们可以简单地用 proxySendHTTPRequest 替换 sendHTTPRequest 的位置,而不需要做任何重大更改。

    想象一下,如果将来网络性能有所提高,或者由于某些其他原因,我们不再需要合并HTTP请求。在这一点上,如果我们使用以前的设计,我们将不得不再次大规模地更改代码。在当前的代码设计中,我们可以简单地替换函数名。

    事实上,这个编码技巧通常被称为设计模式中的代理模式

    所谓的代理模式,其实在现实生活中很好理解。

    • 比方说,你想访问一个网站,但你不想泄露你的IP地址。那么你可以使用VPN,先访问你的代理服务器,然后通过代理服务器访问目标网站。这样目标网站就无法知道你的IP地址了。
    • 有时候,你会把你的真实服务器隐藏在Nginx服务器后面,让Nginx服务器为你的真实服务器处理一些琐碎的操作。

    这些都是现实生活中代理模式的例子。

    我们不需要为代理模式(或任何其他设计模式)的正式定义而烦恼,我们只需要知道,当客户端没有直接访问它的便利(或能力)时,我们可以提供代理功能(或对象)来控制对目标功能(或对象)的访问即可。客户机实际上访问代理函数(或对象),代理函数对请求进行一些处理,然后将请求传递给目标。


    如果您有任何问题或认为本文需要改进,非常欢迎您留言。您的建议和批评对我非常有用。谢谢您。


    起源地下载网 » 改善应用程序性能和代码质量:通过代理模式组合HTTP请求

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元