Sukka's Blog

童话只美在真实却从不续写

使 Disqus 不再拖累性能和页面加载

Sukka's Avatar 2019-12-13 技术向

  1. 1. Disqus 在国内抽风的 workaround
  2. 2. 禁用 Disqus 的追踪和返利链接
  3. 3. Disqus Lazyload

作为第三方社会化评论的鼻祖,Disqus 是目前最受欢迎的评论系统。根据 Wappalyzer 的数据,有超过 10 万的网站正在使用 Disqus。但是笨重的 Disqus 评论对于网站加载来说堪称噩梦 ……

Disqus 在国内抽风的 workaround

Disqus 在国内全面抽风那是「国情」所致,没什么好办法解决。我写了一个解决方案 DisqusJS,自动判断访客的 Disqus 可访问性,对于无法连通 Disqus 的访客则通过 Disqus API 在前端页面渲染一个评论列表,对国内访客的体验还是不错的。

禁用 Disqus 的追踪和返利链接

Disqus 的评论框会加载一大堆的 AFF 链接和追踪链接(可能就是 Disqus 维持免费服务同时却能盈利的原因吧),F12 打开控制台可以发现各种域名各种类型的请求(collect.gifreferrer.phpaff.php)刷个不停。
好在 Disqus 提供了手动关闭这些请求的开关。前往 Disqus 管理后台Settings -> Advanced -> Deeply integrate Disqus with your community,将「Track」和「Affiliate links」禁用掉即可。

6.png

「Affiliate links」除了会产生拖累加载的额外请求,还会导致页面出现其它 Bug,参见「使用 Disqus 后,网页中莫名出现的可点击链接」一文。

Disqus Lazyload

即使禁用了追踪和返利使其不再加载无关请求,Disqus 本身依然是非常笨重的:各种 CSS/JS/Font/API 加起来请求不小于 2MB,而且是伴随着页面一起加载的。当 Disqus 加载时,浏览器会在主线程中同步解析、渲染 Disqus,造成卡顿;更重要的是,Disqus 评论框位于页面底部(对于大部分网站来说都是如此),在页面加载后的很长一段时间用户都不会和 Disqus 发生互动,而宝贵的带宽和性能就被这样浪费了。

0.gif

使用 Pagespeed Insight 测试我的博客的文章页面,可以看到所有的问题都聚焦在 Disqus 上:

1.png
2.png
3.png

在「图片 lazyload 的学问和在 Hexo 上的最佳实践」一文中我就已经提到过:任何资源包括媒体资源、DOM 节点、非关键 CSS 和 JS,都可以做 lazyload。Disqus 自然不例外。

在实现 lazyload 之前,我们需要先知道这几点:

  • 研究表明 Disqus 有助于 SEO,Disqus 和 Akismet 的合作使你的网站上不太有可能出现太多垃圾评论,而优质内容都是有助于在搜索引擎中获得更高权重的。
  • 本文写于 9012 年,已经有 92% 的浏览器已经兼容 IntersectionObserver API 了。除非你真的很照顾 IE 用户,否则不应该继续使用监听页面滚动事件(onscroll)的方法实现 lazyload,而且
  • Google 的爬虫有针对 IntersectionObserver API 优化,因此如果你的 lazyload 库或者代码在实现时使用的是 IntersectionObserver API,那么 Google 可以更好地抓取被 lazyload 的内容。

7.gif

接下来就该上代码了。

function loadDisqus() {
// Disqus 安装代码
var d = document, s = d.createElement('script');
s.src = 'https://[你的 Disqus shortname].disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
window.disqus_config = function () {
this.page.url = [你的页面 URL];
this.page.identifier = [你的页面的唯一辨识符];
};
// 如果你和我一样在用 DisqusJS,loadDisqus() 里就应该是 DisqusJS 的初始化代码 new DisqusJS({...})
}

// 通过检查 window 对象确认是否在浏览器中运行
var runningOnBrowser = typeof window !== "undefined";
// 通过检查 scroll 事件 API 和 User-Agent 来匹配爬虫
var isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent);
// 检查当前浏览器是否支持 IntersectionObserver API
var supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window;

// 一个小 hack,将耗时任务包裹在 setTimeout(() => { }, 1) 中,可以推迟到 Event Loop 的任务队列中、等待主调用栈清空后才执行,在绝大部分浏览器中都有效
// 其实这个 hack 本来是用于优化骨架屏显示的。一些浏览器总是等 JavaScript 执行完了才开始页面渲染,导致骨架屏起不到降低 FCP 的优化效果,所以通过 hack 将耗时函数放到骨架屏渲染完成后再进行。
setTimeout(function () {
if (!isBot && supportsIntersectionObserver) {
// 当前环境不是爬虫、并且浏览器兼容 IntersectionObserver API
var disqus_observer = new IntersectionObserver(function(entries) {
// 当前视窗中已出现 Disqus 评论框所在位置
if (entries[0].isIntersecting) {
// 加载 Disqus
loadDisqus();
// 停止当前的 Observer
disqus_observer.disconnect();
}
}, { threshold: [0] });
// 设置让 Observer 观察 #disqus_thread 元素
disqus_observer.observe(document.getElementById('disqus_thread'));
} else {
// 当前环境是爬虫、或当前浏览器其不兼容 IntersectionObserver API
// 直接加载 Disqus
loadDisqus();
}
}, 1);

对 Disqus 进行 lazyload、并加一点 特技 hack 以后,Pagespeed Insight 的分数 Duang 一下子就上来了。

4.png

本文作者 : Sukka
本文采用 CC BY-NC-SA 4.0 许可协议。转载和引用时请注意遵守协议!
本文链接 : https://blog.skk.moe/post/prevent-disqus-from-slowing-your-site/

本文最后更新于 天前,文中所描述的信息可能已发生改变