timeoutFn(() => {
// Find all links & Connect them to IO if allowed
(options.el || document).querySelectorAll('a').forEach(link => {
// If the anchor matches a permitted origin
// ~> A `[]` or `true` means everything is allowed
if (!allowed.length || allowed.includes(link.hostname)) {
// If there are any filters, the link must not match any of them
isIgnored(link, ignores) || observer.observe(link);
}
});
}, {
timeout: options.timeout || 2000,
});
预加载的好与不好
预加载意味着会发更多的请求,并且很可能用户最终也不会使用,这些流量会造成更大的服务器压力,换句话就是你会为此花更多钱。
好处就是用户体验会好点,对于网速很快的用户来说提升只是一点点,对于网速稍慢的用户来说提升会更明显。
参考资料
关于 React.lazy 和动态 import 的一些测试
参考 Lazy loading (and preloading) components in React 16.6 | by Rodrigo Pombo | HackerNoon.com | Medium 做了一些测试。
不做动态 import
加上动态 import
加上动态 import 并提前下载文件
加上动态 import 并在鼠标 hover 时下载文件
这里就算鼠标多次 hover ,也只会发一个下载文件的请求的。
封装一下
如果动态 import 的组件 A 里面还动态 import 了其它的组件 B
这种情况的话,是会在需要展示组件 B 的时候才去下载组件 B 的代码,因为你在鼠标移上去的时候只预加载了组件 A 。
直接使用 loadable-components 库来做预加载
react-router 推荐的 code splitting 库是 loadable-components ,这个库是支持 预加载 功能的。
按路由切割代码后能做预加载吗
上面说的都是页面中某个次要内容的代码分割和预加载,下面来进入正题,按路由切割代码后,能在当前路由预加载其它路由的代码吗?
自己封装一下 Link
我们可以把 react-router-dom 库的 Link 组件再封装一层来实现预加载。
把路径以及对应的组件定义为数组,方便我们封装的 LinkWithPreload 去遍历数组找到组件,然后去执行组件的 preload 就好了。
在需要使用 Link 的地方就
<LinkWithPreload to='/xxx'>查看</LinkWithPreload>
就可以了。这里是鼠标移上去的时候预加载,如果你想,也可以改为使用 Intersection Observer ,判断 Link 组件进入可见区域时就预加载。
在什么时候进行预加载也是一种权衡,尽早预加载可以保证跳转页面的时候资源已经加载好了,但是会不可避免造成一些不必要的加载,因为你不知道用户会访问哪些页面。(当然如果你想你可以结合统计工具的数据,只对用户经常访问的页面做预加载来增加命中率 hhh)
直接使用 quicklink 库
https://github.com/GoogleChromeLabs/quicklink
它是监听的 Link 进入可视区域就进行预加载。
在 create-react-app 中使用:https://github.com/GoogleChromeLabs/quicklink/blob/master/demos/spa/README.md
使用这个库会需要配置 webpack-route-manifest 插件,这个插件会生成下面这个东西,然后就可以根据路由去预加载了。
quicklink 的相关实现见 https://github.com/GoogleChromeLabs/quicklink/blob/master/src/react-chunks.js#L61 和 https://github.com/GoogleChromeLabs/quicklink/blob/master/src/index.mjs#L60 。
它是等路由组件进入可视区域后,然后拿到路由组件中所有 a 标签,然后再对应去做预加载。
总结
为了减少加载一个页面时需要下载的代码,我们可以:
代码切割是为了减少必要代码的体积,预加载是为了低优先级组件代码在需要时也能尽快展示。
preload、prefetch、动态 import 区别
preload 和 prefetch 是 HTML link 标签的一个用法,用于提示浏览器去提前下载资源。preload 是希望提前下载当前页面的资源。prefetch 是希望提前下载其它页面的资源。
动态 import 是 JS 的一个语法,Webpack 打包时会把动态 import 的部分打包为单独的文件。可以用于实现按路由切割代码,或者把弹窗等低优先级界面代码从主界面代码切割出去,这样来加快主界面的加载速度。
当你希望预加载资源时,是使用 link 的 prefetch 还是说动态 import ,其实结果都是一样的,可以结合项目用的库来看怎么实现简单怎么来。