【问题标题】:Reduce the impact of third-party code (zendesk)减少第三方代码的影响(zendesk)
【发布时间】:2020-02-16 15:38:38
【问题描述】:

<script
  id="ze-snippet"
  src="https://static.zdassets.com/ekr/snippet.js?key=some_zendesk_key"
/>

我正在尝试优化我的网站性能。我已经面临第三方代码对我的性能的巨大影响,我认为我所有的包的大小都比 zendesk 代码小。如何在不影响主线程的情况下加载它?我应该使用async 还是defer 标签?或者哪种方法更适合这种情况?

【问题讨论】:

  • IIRC,我曾尝试在 Zendesk Chat 的开发中使用异步标签,但它会导致很多问题。我基本上得出的结论是,该脚本无法不影响您的性能,因为它只是加载了许多其他脚本。
  • 这里也一样。我正在将这个脚本加载到 react gatsby 应用程序中。有趣的是,如果您对 zendesk.com 进行审核,大小为 354 KB,阻塞时间为 638 毫秒。我觉得审核太敏感了,因为加载时间的真实感觉实际上很好。

标签: javascript zendesk lighthouse


【解决方案1】:

这似乎是一个折磨了这么多人却没有明确解决办法的问题。

我设法通过添加此配置来减少阻塞时间。

window.zESettings = {
    webWidget: {
      chat: {
        connectOnPageLoad: false
      }
    }
  };

参考https://developer.zendesk.com/embeddables/docs/widget/settings#connectonpageload

ps 我对我的 zendesk 帮助台“domain.zendesk.com”进行了性能测试,结果更糟

【讨论】:

    【解决方案2】:

    我最近遇到了这个问题,并且只在您到达文档的某个点时使用一个用于加载 zendesk 脚本的函数进行了这个 hack。我知道这有点脏,但它有效:

    <script defer type="text/javascript">
        (function($, win) {
            $.fn.inViewport = function(cb) {
                return this.each(function(i,el){
                    function visPx(){
                        var H = $(this).height(),
                        r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
                        return cb.call(el, Math.max(0, t>0? H-t : (b<H?b:H)));  
                    }  visPx();
                    $(win).on("resize scroll", visPx);
                });
            };
        }(jQuery, window));
    
    
    $('#trigger_div').inViewport(function(px){
        if(px) {
    
        //zopim code
    
        }
    });
    

    【讨论】:

      【解决方案3】:

      https://www.newmediacampaigns.com/blog/maintaining-great-site-performanc-using-zendesk-web-widget这篇文章开始,我已经实现了一个解决方案,它可以将加载时间显着减少至少 3 秒(在 Google Lighthouse 中)。

      我在 HTML 中创建了一个假按钮,该按钮将加载 Zendesk 脚本并在单击时打开小部件。它还将加载一个 localStorage 项,以防止在后续页面加载时发生这种情况。

      ⚠️ 警告:

      代码很大程度上依赖于小部件当前的实现方式(例如,它希望页面上出现#launcher#webWidget 元素),因此它可以在原始代码更改后立即中断,但在至少在他们修复之前,我们会改进加载时间。

      这是代码中最重要的部分:

      HTML 按钮

      <button class="zendesk-button">
        <span class="left-icon">
          <!-- here you insert the icon -->
        </span>
        <span class="text">Chat</span>
      </button>
      

      JavaScript 代码

      // select the button
      const zendeskButton = document.querySelector('.zendesk-button');
      
      // add the script to the page
      const loadZendeskScript = () => {
        const zenDeskScript = document.createElement("script");
        zenDeskScript.id = "ze-snippet";
        zenDeskScript.src = "https://static.zdassets.com/ekr/snippet.js?key=HERE_YOU_INSERT_YOUR_KEY";
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] || document.getElementsByTagName('script')[0].parentNode).insertBefore(zenDeskScript, null);
      };
      
      // a poller that waits for a condition and executes a callback
      const poller = (comparison, callback, timerStep = 250, maxTime = 5000) => {
        // why setTimeout instead of setInterval
        // https://stackoverflow.com/questions/8682622/using-setinterval-to-do-simplistic-continuous-polling
        let currTime = 0;
        const checkCondition = () => {
          // `comparison` is a function so the condition is always up-to-date
          if (comparison() === true) {
            callback();
          } else if (currTime <= maxTime) {
            currTime += timerStep;
            setTimeout(checkCondition, timerStep);
          }
        };
        checkCondition(); // calling the function
      };
      
      // load the script and execute a callback if provided
      const loadZendeskChat = callback => {
        loadZendeskScript();
        if (callback) {
          callback();
        }
      };
      
      // this function opens the chat
      const openZendeskChat = () => {
        poller(
          () => {
            // check that zendesk-related functions are available
            return typeof zE !== 'undefined';
          },
          () => {
            // open the widget
            zE('webWidget', 'open');
            poller(
              () => {
                // check that the elements exist and that the opacity is already set to "1"
                const launcher = document.querySelector('#launcher');
                const webWidget = document.querySelector('#webWidget');
                return launcher !== null && webWidget !== null && webWidget.style.opacity === '1';
              },
              () => {
                // hide the fake button
                zendeskButton.style.opacity = '0';
                // save in localStorage
                localStorage.setItem('zd_hasOpened', 'true');
              }
            );
          }
        );
      };
      
      // zendesk management
      if (localStorage.getItem('zd_hasOpened')) {
        // load the zendesk widget if we find that it was opened
        loadZendeskChat();
      } else {
        // show the fake button if it's the first time it shows
        zendeskButton.style.opacity = '1';
      }
      // This will run when the .zendesk-button element is clicked
      zendeskButton.addEventListener('click', () => {
        // add a 'Loading' text to the button, as the widget will take some time to load (between 1 and 2 seconds on my laptop)
        zendeskButton.querySelector('.text').innerHTML = 'Loading';
        // load the zendesk widget
        // open the widget and hide the fake button
        loadZendeskChat(openZendeskChat);
      });
      

      关于样式,我几乎复制了原始小部件中的样式,将 em 转换为像素,但我想强调的部分是焦点样式,因为我认为它有助于告诉用户正在发生的事情.

      .zendesk-button:focus {
        outline: none;
        box-shadow: inset 0 0 0 0.21429rem rgb(255 255 255 / 40%) !important;
      }
      

      【讨论】:

        猜你喜欢
        • 2022-05-12
        • 1970-01-01
        • 2018-11-08
        • 1970-01-01
        • 2012-05-30
        • 2016-11-11
        • 2019-02-14
        • 2013-04-28
        • 2016-12-15
        相关资源
        最近更新 更多