<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>前端 on Colinx Blog</title><link>/tags/%E5%89%8D%E7%AB%AF/</link><description>Recent content in 前端 on Colinx Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 09 May 2022 00:00:00 +0000</lastBuildDate><atom:link href="/tags/%E5%89%8D%E7%AB%AF/index.xml" rel="self" type="application/rss+xml"/><item><title>论如何下载任意网站视频</title><link>/posts/%E8%AE%BA%E5%A6%82%E4%BD%95%E4%B8%8B%E8%BD%BD%E4%BB%BB%E6%84%8F%E7%BD%91%E7%AB%99%E8%A7%86%E9%A2%91/</link><pubDate>Mon, 09 May 2022 00:00:00 +0000</pubDate><guid>/posts/%E8%AE%BA%E5%A6%82%E4%BD%95%E4%B8%8B%E8%BD%BD%E4%BB%BB%E6%84%8F%E7%BD%91%E7%AB%99%E8%A7%86%E9%A2%91/</guid><description>
&lt;!-- # 论如何下载任意网站视频 -->
&lt;p>视频已然成为当今互联网上信息传播的一个重要载体，有时会需要下载一些网上某个站点的视频插入 PPT，或者视频素材，无论是自己用抑或单纯是给朋友帮个忙，掌握一些使用的下载视频的小技巧总是不会错的，这里分享一些自用的小技巧，包括热门站点下载工具，以及应对冷门网站视频下载的技巧，应该可以覆盖 99.9% 的视频下载场景&lt;/p>
&lt;h2 id="热门网站电影电视剧下载">
热门网站电影/电视剧下载
&lt;a href="#%e7%83%ad%e9%97%a8%e7%bd%91%e7%ab%99%e7%94%b5%e5%bd%b1%e7%94%b5%e8%a7%86%e5%89%a7%e4%b8%8b%e8%bd%bd" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;p>这种其实建议直接找对应资源而不是从源站点下载，百度云，阿里云盘等找资源的方式我就不再赘述了，网上教程多的是。如果是电影资源或者是欧美、日韩的剧，可以搜索 BT 资源自行下载。&lt;/p>
&lt;p>这里安利一个油猴脚本：&lt;a href="https://greasyfork.org/zh-CN/scripts/329484-%E8%B1%86%E7%93%A3%E8%B5%84%E6%BA%90%E4%B8%8B%E8%BD%BD%E5%A4%A7%E5%B8%88-1%E7%A7%92%E6%90%9E%E5%AE%9A%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1-%E9%9F%B3%E4%B9%90-%E5%9B%BE%E4%B9%A6%E4%B8%8B%E8%BD%BD">豆瓣资源下载大师&lt;/a>，可以在豆瓣的影视详情页右侧显示有资源的站点，非常方便&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205091548956.png" alt="image-20220509144533549">&lt;/p>
&lt;p>分享下个人常用的下载站点：&lt;/p>
&lt;ul>
&lt;li>欧美资源下载：&lt;a href="https://www.1337x.to/">1337X&lt;/a>&lt;/li>
&lt;li>欧美资源下载：&lt;a href="https://piratebay.live/">海盗湾&lt;/a>&lt;/li>
&lt;li>动漫资源下载：&lt;a href="https://acg.rip/?term=JOJO%E7%9A%84%E5%A5%87%E5%A6%99%E5%86%92%E9%99%A9">ACG RIP&lt;/a>&lt;/li>
&lt;li>中文字幕下载：&lt;a href="http://zimuku.org">字幕库&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>个人推荐的下载工具：&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.qbittorrent.org">qBittorrent&lt;/a>：强推，老牌专业 BT 工具，有图形化界面，&lt;a href="https://hub.docker.com/r/linuxserver/qbittorrent">支持 Docker 部署&lt;/a>且带 Web 界面&lt;/li>
&lt;li>&lt;a href="http://aria2.github.io">aria2&lt;/a>：强大的命令行下载工具，灵活但上手成本略高，可&lt;a href="https://ariang.mayswind.net/zh_Hans/">自行部署 Web GUI 界面&lt;/a>，也可使用&lt;a href="http://ariang.mayswind.net/latest">公开版本 demo&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://motrix.app">Motrix&lt;/a>：高颜值跨平台的下载工具，有漂亮的 GUI 界面，底层基于 aria2&lt;/li>
&lt;/ul>
&lt;p>Tracker 列表：&lt;/p>
&lt;ul>
&lt;li>一个独立的收集 trackerlist 的页面：&lt;a href="https://trackerslist.com/#/zh">https://trackerslist.com/#/zh&lt;/a>&lt;/li>
&lt;li>通用 tracker list：&lt;a href="https://github.com/ngosang/trackerslist">ngosang/trackerslist&lt;/a>&lt;/li>
&lt;li>动漫资源 tracker list：&lt;a href="https://github.com/DeSireFire/animeTrackerList">animeTrackerList&lt;/a> (๑•̀ㅂ•́)و✧&lt;/li>
&lt;/ul>
&lt;h2 id="热门站点普通视频资源下载">
热门站点普通视频资源下载
&lt;a href="#%e7%83%ad%e9%97%a8%e7%ab%99%e7%82%b9%e6%99%ae%e9%80%9a%e8%a7%86%e9%a2%91%e8%b5%84%e6%ba%90%e4%b8%8b%e8%bd%bd" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;p>如果是 UGC 内容，比如 B 站用户上传的视频，那么 BT 通常是没有资源的，需要单独从源网站下载。不过既然是热门站点，都有很多人造过轮子了，这里推荐几个&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://github.com/ytdl-org/youtube-dl">YouTube-DL&lt;/a>&lt;/strong>&lt;/p>
&lt;p>一款强大的命令行视频下载工具，别看人家名字只写了 youtube，但其实国内爱优腾都是支持的。命令行调用也非常简洁，&lt;a href="https://github.com/ytdl-org/youtube-dl">知乎也有教程&lt;/a>需要的话可以瞅瞅。&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://github.com/yt-dlp/yt-dlp">YT-DLP（YouTube DownLoader Plus）&lt;/a>&lt;/strong>&lt;/p>
&lt;p>YouTube-DL 的一个分支，包括一些 bug 修复和增强的特性&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://github.com/iawia002/lux">Lux（原名 Annie）&lt;/a>&lt;/strong>&lt;/p>
&lt;p>Golang 编写的一个视频下载工具，同样支持国内站点&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://www.flvcd.com/index.htm">硕鼠&lt;/a>&lt;/strong>&lt;/p>
&lt;p>很早之前就出的一款免费视频下载合并工具，主要针对国内视频网站，但是像腾讯视频这种之前发过律师函，人家就迫不得已取消了支持。Windows 版，有界面，对于不是那么热门但是稍微又有点名气的网站支持较好&lt;/p>
&lt;h2 id="冷门站点普通视频资源下载">
冷门站点普通视频资源下载
&lt;a href="#%e5%86%b7%e9%97%a8%e7%ab%99%e7%82%b9%e6%99%ae%e9%80%9a%e8%a7%86%e9%a2%91%e8%b5%84%e6%ba%90%e4%b8%8b%e8%bd%bd" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;p>冷门站点的资源得我们自己动手了，不过利用浏览器的开发人员工具还是很容易获取的资源的。右键找到开发人员选项打开开发人员工具，可以点击左上角的按钮选择网页元素，找到&lt;code>&amp;lt;video&amp;gt;&lt;/code>标签，里面一般会有一个链接地址，复制地址打开即可。&lt;/p>
&lt;p>这种简单的视频嵌入很容易下载，浏览器工具也很容易嗅探到。比如可以使用&lt;code>专业视频下载工具&lt;/code>插件，你可以&lt;a href="https://ext.chrome.360.cn/webstore/detail/noaehhegaeigebicejggjdecdkfphced">访问 360 插件中心下载&lt;/a>。这种工具很多，这里不再赘述&lt;/p>
&lt;p>链接后缀为&lt;code>mp4&lt;/code>的一般来说都是说明该网页上面的视频只是从那一个文件加载的，没有经过分片和其他处理。如果没有后缀名，或者是&lt;code>flv&lt;/code>、&lt;code>ts&lt;/code>或者链接含有&lt;code>m3u8&lt;/code>字样的，说明该网页的资源是经过分片的，需要我们动点手段。&lt;/p>
&lt;h2 id="冷门站点-m3u8-动态分片视频资源下载">
冷门站点 m3u8 动态分片视频资源下载
&lt;a href="#%e5%86%b7%e9%97%a8%e7%ab%99%e7%82%b9-m3u8-%e5%8a%a8%e6%80%81%e5%88%86%e7%89%87%e8%a7%86%e9%a2%91%e8%b5%84%e6%ba%90%e4%b8%8b%e8%bd%bd" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;p>以中国庭审网的庭审录像视频为例，打开开发者工具定位到视频的部分发现 video 标签里面的 url 很奇怪，访问该链接也并不能访问到有效的视频。这种网页一般都是通过 m3u8 来下发分片文件的信息&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205091548957.png" alt="image-20220509151813071">&lt;/p>
&lt;p>打开开发者工具的网络选项卡，监听网络活动，点击播放视频，会多出来很多条目分别代表每一个网络请求。在搜索框输入 m3u8 来进行过滤。定位到该请求后可以在新标签页打开，保存这个 m3u8 文件。&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205091548958.png" alt="image-20220509144410278">&lt;/p>
&lt;p>之后我们可以利用 ffmpeg 载入这个 m3u8 文件并进行合并，如有需要可一并进行转码操作&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">ffmpeg -i xxxx.m3u8 -c xxxx.mp4
&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果报错提示不支持的 protocol，那么需要再加个参数让 ffmpeg 使用 http 下载&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">ffmpeg -protocol_whitelist concat,file,http,https,tcp,tls,crypto -i xxxx.m3u8 -c copy xxxx.mp4
&lt;/code>&lt;/pre>&lt;/div>&lt;p>接下来等待命令跑完，我们就可以得到需要的视频文件了。&lt;/p>
&lt;p>其他常用处理命令&lt;/p>
&lt;p>使用&lt;code>-i&lt;/code>参数读取文件，查看详细参数&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">ffmpeg -i xxxx.mp4
&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用 ffmepg 提取视频中的音频部分，方便后续处理。比如要生成字幕或是转写为文本，省的上传几百兆的视频文件。&lt;a href="https://jianwai.youdao.com/">网易见外工作台&lt;/a>做这些很方便，而且免费额度也很足，安利一波&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">ffmpeg -i xxxx.mp4 -vn -codec copy xxxx.aac
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205091548959.png" alt="image-20220509153021601">&lt;/p>
&lt;p>解析并下载 m3u8 视频的其他方案&lt;/p>
&lt;ul>
&lt;li>使用硕鼠解析：https://www.flvcd.com/index.htm&lt;/li>
&lt;li>使用 Chrome 插件：&lt;a href="https://chrome.google.com/webstore/detail/video-downloader-cococut/gddbgllpilhpnjpkdbopahnpealaklle">CoCoCut&lt;/a>，&lt;a href="https://github.com/xifangczy/cat-catch">猫抓 (cat-catch)&lt;/a>&lt;/li>
&lt;li>使用油猴脚本：&lt;a href="https://greasyfork.org/zh-CN/scripts/440577-m3u8-%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD-vip%E8%A7%A3%E6%9E%90%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD-%E7%BD%91%E7%AB%99%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD">m3u8-downloader&lt;/a>，配套工具&lt;a href="https://github.com/Momo707577045/m3u8-downloader">地址&lt;/a>&lt;/li>
&lt;li>使用软件：&lt;a href="http://www.neatdownloadmanager.com/index.php/en/">NeatDownloadManager&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>以上&lt;/p></description></item><item><title>前端静态资源加载的一些优化</title><link>/posts/%E5%89%8D%E7%AB%AF%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E5%8A%A0%E8%BD%BD%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BC%98%E5%8C%96/</link><pubDate>Fri, 06 May 2022 00:00:00 +0000</pubDate><guid>/posts/%E5%89%8D%E7%AB%AF%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E5%8A%A0%E8%BD%BD%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BC%98%E5%8C%96/</guid><description>
&lt;!-- # 前端静态资源加载的一些优化 -->
&lt;p>最近在折腾优化博客，由于全站都是部署在 Netlify、Vercel 的 CDN 上，都是海外节点，国内访问延迟高，在想办法优化下访问速度和体验。线路部分的优化可以看另一篇文章&lt;a href="https://blog.colinx.one/posts/%E5%9B%BD%E5%A4%96%E9%9D%99%E6%80%81%E7%BD%91%E7%AB%99%E6%89%98%E7%AE%A1%E5%9C%A8%E5%9B%BD%E5%86%85%E9%80%9F%E5%BA%A6%E5%AF%B9%E6%AF%94%E5%8F%8A%E7%BA%BF%E8%B7%AF%E4%BC%98%E5%8C%96/">国外静态网站托管服务商国内速度对比及线路优化&lt;/a>。这篇文章来探讨下前端 CSS 和 JS 资源的加载。&lt;/p>
&lt;p>优化目标主要就两个：&lt;/p>
&lt;ul>
&lt;li>尽可能快，但是不希望我引入的辅助性第三方库影响到页面体验，不要阻塞主要内容渲染&lt;/li>
&lt;li>为了快第三方静态资源肯定是上 CDN，但是要有容灾，CDN 挂了要能 fallback 到其他 url&lt;/li>
&lt;/ul>
&lt;h2 id="静态资源异步加载">
静态资源异步加载
&lt;a href="#%e9%9d%99%e6%80%81%e8%b5%84%e6%ba%90%e5%bc%82%e6%ad%a5%e5%8a%a0%e8%bd%bd" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;p>&lt;code>prefetch&lt;/code>、&lt;code>preload&lt;/code>这些预加载技术暂且不谈，博客站点没那么多资源。这里主要是用&lt;code>async&lt;/code>和&lt;code>defer&lt;/code>来控制脚本异步加载，以避免阻塞 DOM 解析和页面渲染。&lt;/p>
&lt;p>使用&lt;code>async&lt;/code>异步加载，对于&lt;a href="https://github.com/vinta/pangu.js/">pangu&lt;/a>这种会影响到内容呈现的使用&lt;code>async&lt;/code>，对于统计类第三方库使用&lt;code>defer&lt;/code>延迟加载，到 DOM 加载完再执行&lt;/p>
&lt;p>有些第三方库需要手动 init，这样就不能使用&lt;code>defer&lt;/code>、&lt;code>async&lt;/code>关键字加载资源了，&lt;strong>&lt;code>defer&lt;/code>和&lt;code>async&lt;/code>关键字只适用于远程资源&lt;/strong>，本以为把远程资源的&lt;code>&amp;lt;script&amp;gt;&lt;/code>和内嵌在 HTML 里用来 init 的&lt;code>&amp;lt;script&amp;gt;&lt;/code>都加上&lt;code>defer&lt;/code>就可以利用它顺序加载的特性解决这个问题，结果发现不是这样的。。。。异步打乱脚本执行顺序，init 脚本不等待资源下载完毕会先执行。利用好&lt;code>onload&lt;/code>事件可以解决这个问题。&lt;/p>
&lt;p>before&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-html" data-lang="html">&amp;lt;&lt;span style="color:#f92672">script&lt;/span> &lt;span style="color:#a6e22e">src&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;https://cdn.jsdelivr.net/npm/pangu@4/dist/browser/pangu.min.js&amp;#34;&lt;/span>&amp;gt;&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&amp;lt;&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;span style="color:#a6e22e">pangu&lt;/span>.&lt;span style="color:#a6e22e">spacingElementByClassName&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;post&amp;#39;&lt;/span>);
&lt;span style="color:#a6e22e">pangu&lt;/span>.&lt;span style="color:#a6e22e">spacingElementByTagName&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;p&amp;#39;&lt;/span>);
document.&lt;span style="color:#a6e22e">addEventListener&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;DOMContentLoaded&amp;#39;&lt;/span>, () =&amp;gt; {
&lt;span style="color:#a6e22e">pangu&lt;/span>.&lt;span style="color:#a6e22e">autoSpacingPage&lt;/span>();
});
&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>after&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-html" data-lang="html">&amp;lt;&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">panguSpaing&lt;/span>() {
&lt;span style="color:#a6e22e">pangu&lt;/span>.&lt;span style="color:#a6e22e">spacingElementByClassName&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;post&amp;#39;&lt;/span>);
&lt;span style="color:#a6e22e">pangu&lt;/span>.&lt;span style="color:#a6e22e">spacingElementByTagName&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;p&amp;#39;&lt;/span>);
document.&lt;span style="color:#a6e22e">addEventListener&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;DOMContentLoaded&amp;#39;&lt;/span>, () =&amp;gt; {
&lt;span style="color:#75715e">// listen to any DOM change and automatically perform spacing via MutationObserver()
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#a6e22e">pangu&lt;/span>.&lt;span style="color:#a6e22e">autoSpacingPage&lt;/span>();
});
}
&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&amp;lt;&lt;span style="color:#f92672">script&lt;/span> &lt;span style="color:#a6e22e">async&lt;/span> &lt;span style="color:#a6e22e">onload&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;panguSpaing()&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">src&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;https://cdn.jsdelivr.net/npm/pangu@4/dist/browser/pangu.min.js&amp;#34;&lt;/span>&amp;gt;&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>除了&lt;code>onload&lt;/code>还有&lt;code>onerror&lt;/code>，还可以利用&lt;code>onerror&lt;/code>事件在资源加载失败时 fallback 到其他 CDN，详见下文&lt;/p>
&lt;p>这里跑了个测试看下优化前后的差距&lt;/p>
&lt;p>&lt;strong>优化前&lt;/strong>&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205062117479.png" alt="image-20220506193639029">&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205062117127.png" alt="image-20220506193800266">&lt;/p>
&lt;p>First Contentful Pain Time 在 1.5s，整个页面到 1.5s 才能可见，DOM 加载总时间达到了 2.5s&lt;/p>
&lt;p>本来我都已经把首页不需要加载的三方库都拿走了，但是还剩下一个，这个用于前端性能监控的 js 阻塞了渲染，挂的是腾讯云的 CDN，国内快到飞起，国外就卡到不行（作为对比上图里从 jsdelivr 加载的 js 也是快到飞起，墙内就慢得一批）&lt;/p>
&lt;p>&lt;strong>优化后&lt;/strong>&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205062117498.png" alt="image-20220506193652188">&lt;/p>
&lt;p>优化后页面没有再阻塞，0.8s 页面就可用了，总 DOM 加载时间只有 1.5s，相较之前简直直接起飞。&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205071426038.png" alt="cn">&lt;/p>
&lt;p>国内某检测平台的结果也显示优化效果明显&lt;/p>
&lt;h2 id="静态资源-fallback-加载">
静态资源 Fallback 加载
&lt;a href="#%e9%9d%99%e6%80%81%e8%b5%84%e6%ba%90-fallback-%e5%8a%a0%e8%bd%bd" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;p>国内好用的静态资源 CDN 还真没有，新浪那种只提供那么几个热门的库完全不符合需求，BootCDN 炸了不是一次两次，字节 CDN 的资源 URL 有够 ugly，URL 里面还带节点信息多半后面会出问题。360 奇舞 CDN 之前也换过域名、备案出问题，感觉每一个能省心用。七牛的目前看上去还行，也不知道后面会不会出什么幺蛾子。。。为了稳妥起见 + 照顾全球的访客，还是优先使用的 cloudflare 和 jsdelivr 的 CDN&lt;/p>
&lt;p>网站主要三方库都是通过 jsdelivr 和 cloudflare 引入的，但是毕竟是海外的节点不知道哪一天就被墙了，所以还要为墙内的访客准备一个 fallback 方案。这里利用到&lt;code>script&lt;/code>标签的&lt;code>onerror&lt;/code>事件&lt;/p>
&lt;p>现代浏览器都支持&lt;code>script&lt;/code>和&lt;code>link&lt;/code>标签上的&lt;code>onload&lt;/code>和&lt;code>onerror&lt;/code>事件，详细支持情况可以查看这里&lt;/p>
&lt;p>&lt;a href="https://pie.gd/test/script-link-events/">https://pie.gd/test/script-link-events/&lt;/a>&lt;/p>
&lt;p>关于&lt;code>onerror&lt;/code>，中文互联网上有好几篇文章说他会捕获&lt;code>script&lt;/code>标签里的代码的执行错误。。。简直离谱。稍微查下 MDN 之类的文档就可以发现这玩意本来就是只捕获资源加载错误的&lt;/p>
&lt;blockquote>
&lt;p>The onerror event is triggered if an error occurs while loading an external file (e.g. a document or an image).&lt;/p>
&lt;p>&lt;a href="https://www.w3schools.com/jsref/event_onerror.asp">https://www.w3schools.com/jsref/event_onerror.asp&lt;/a>&lt;/p>
&lt;/blockquote>
&lt;p>利用好这个特性，就可以实现在资源加载失败时 fallback 从另一个 url 加载资源。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-html" data-lang="html">&amp;lt;&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">fallbackJSloader&lt;/span>(&lt;span style="color:#a6e22e">url&lt;/span>, &lt;span style="color:#a6e22e">loadedEvent&lt;/span>) {
&lt;span style="color:#a6e22e">console&lt;/span>.&lt;span style="color:#a6e22e">log&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;Error loading asset, using fallback url&amp;#39;&lt;/span>);
&lt;span style="color:#a6e22e">console&lt;/span>.&lt;span style="color:#a6e22e">log&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;load asset from&amp;#39;&lt;/span>, &lt;span style="color:#a6e22e">url&lt;/span>);
&lt;span style="color:#66d9ef">let&lt;/span> &lt;span style="color:#a6e22e">script&lt;/span> &lt;span style="color:#f92672">=&lt;/span> document.&lt;span style="color:#a6e22e">createElement&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;script&amp;#34;&lt;/span>);
&lt;span style="color:#a6e22e">script&lt;/span>.&lt;span style="color:#a6e22e">type&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;text/javascript&amp;#34;&lt;/span>;
&lt;span style="color:#a6e22e">script&lt;/span>.&lt;span style="color:#a6e22e">src&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">url&lt;/span>;
&lt;span style="color:#a6e22e">script&lt;/span>.&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">true&lt;/span>;
&lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#a6e22e">loadedEvent&lt;/span>)
&lt;span style="color:#a6e22e">script&lt;/span>.&lt;span style="color:#a6e22e">setAttribute&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;onload&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">`&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>&lt;span style="color:#a6e22e">loadedEvent&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">()`&lt;/span>)
document.&lt;span style="color:#a6e22e">body&lt;/span>.&lt;span style="color:#a6e22e">appendChild&lt;/span>(&lt;span style="color:#a6e22e">script&lt;/span>);
}
&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&amp;lt;&lt;span style="color:#f92672">script&lt;/span> &lt;span style="color:#a6e22e">defer&lt;/span> &lt;span style="color:#a6e22e">onload&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;init_gitalk()&amp;#34;&lt;/span>
&lt;span style="color:#a6e22e">onerror&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;fallbackJSloader(&amp;#39;https://cdn.staticfile.org/gitalk/1.7.2/gitalk.min.js&amp;#39;,&amp;#39;init_gitalk&amp;#39;)&amp;#34;&lt;/span>
&lt;span style="color:#a6e22e">src&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js&amp;#34;&lt;/span>&amp;gt;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>CSS 的 fallback 加载同理，此处不再赘述&lt;/p>
&lt;p>优化后如图，在开发者工具中手动 block 资源网站，可以自动 fallback 从另一个 url 加载资源，这下网站的可用性又提升了一点点🤏哈哈哈&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/202205062133393.png" alt="66230832-3581-42DF-9F2F-B817E88DAF4D">&lt;/p>
&lt;h2 id="扩展阅读">
扩展阅读
&lt;a href="#%e6%89%a9%e5%b1%95%e9%98%85%e8%af%bb" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.w3cplus.com/performance/remove-block-rendering.html">消除阻塞页面渲染的资源&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://segmentfault.com/q/1010000000640869">defer 和 async 的区别&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://lengyun.github.io/js/3-2-2dynamicAddCSS.html#%E4%B8%8E%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BDjs%E7%9A%84%E5%8C%BA%E5%88%AB">动态加载 css&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>网站 profile&lt;/strong>工具&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.webpagetest.org">https://www.webpagetest.org&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>