- 做者:陈大鱼头
- 首发地址: github.com/KRISACHAN/y…
- 说明:鱼头的学习记录
根据W3C性能小组的介绍,超过50ms的任务就是长任务。javascript
图片来自使用 RAIL 模型评估性能css
根据上图咱们能够知道,当延迟超过100ms,用户就会察觉到轻微的延迟。html
因此为了不这种状况,咱们可使用两种方案,一种是Web Worker,另外一种是时间切片(Time Slicing)。前端
咱们都知道,JS是单线程,因此当咱们在运行长任务时,容易形成页面假死的状态,虽然咱们能够将任务放在任务队列中,经过异步的方式执行,但这并不能改变JS的本质。java
因此为了改变这种现状,whatwg推出了Web Workers。git
具体的语法不会进行说明,有兴趣的童鞋能够查看MDN Web Worker。github
咱们能够看看使用了Web Worker
以后的优化效果:web
const testWorker = new Worker('./worker.js')
setTimeout(_ => {
testWorker.postMessage({})
testWorker.onmessage = function (ev) {
console.log(ev.data)
}
}, 5000)
// worker.js
self.onmessage = function () {
const start = performance.now()
while (performance.now() - start < 1000) {}
postMessage('done!')
}
复制代码
代码以及截图来自于让你的网页更丝滑性能优化
时间切片是一项使用得比较广的技术方案,它的本质就是将长任务分割为一个个执行时间很短的任务,而后再一个个地执行。微信
这个概念在咱们平常的性能优化上是很是有用的。
例如当咱们须要在页面中一次性插入一个长列表时(固然,一般这种状况,咱们会使用分页去作)。
若是利用时间分片的概念来实现这个功能,咱们可使用requestAnimationFrame
+DocumentFragment
关于这两个API,我一样不会作详细的介绍,有兴趣的能够查看MDN requestAnimationFrame跟MDN DocumentFragment。
这里有两个DEMO,你们能够对比下流畅程度:
未使用时间分片:
<style> * { margin: 0; padding: 0; } .list { width: 60vw; position: absolute; left: 50%; transform: translateX(-50%); } </style>
<ul class="list"></ul>
<script> 'use strict' let list = document.querySelector('.list') let total = 100000 for (let i = 0; i < total; ++i) { let item = document.createElement('li') item.innerText = `我是${i}` list.appendChild(item) } </script>
复制代码
使用时间分片:
<style> * { margin: 0; padding: 0; } .list { width: 60vw; position: absolute; left: 50%; transform: translateX(-50%); } </style>
<ul class="list"></ul>
<script> 'use strict' let list = document.querySelector('.list') let total = 100000 let size = 20 let index = 0 const render = (total, index) => { if (total <= 0) { return } let curPage = Math.min(total, size) window.requestAnimationFrame(() => { let fragment = document.createDocumentFragment() for (let i = 0; i < curPage; ++i) { let item = document.createElement('li') item.innerText = `我是${index + i}` fragment.appendChild(item) } list.appendChild(fragment) render(total - curPage, index + curPage) }) } render(total, index) </script>
复制代码
没有作太多的测评,可是从用户视觉上的感觉来看就是,第一种方案,我就是想刷新都要打好几个转,往下滑的时候也有白屏的现象。
除了上述的生成DOM的方案,咱们一样能够利用Web Api requestIdleCallback
以及ES6 API Generator]
来实现。
一样不会作太多的介绍,详细规则能够看MDN requestIdleCallback以及MDN Generator。
具体实现以下:
<style> * { margin: 0; padding: 0; } .list { width: 60vw; position: absolute; left: 50%; transform: translateX(-50%); } </style>
<ul class="list"></ul>
<script> 'use strict' function gen(task) { requestIdleCallback(deadline => { let next = task.next() while (!next.done) { if (deadline.timeRemaining() <= 0) { gen(task) return } next = task.next() } }) } let list = document.querySelector('.list') let total = 100000 function* loop() { for (let i = 0; i < total; ++i) { let item = document.createElement('li') item.innerText = `我是${i}` list.appendChild(item) yield } } gen(loop()) </script>
复制代码
若是你喜欢探讨技术,或者对本文有任何的意见或建议,很是欢迎加鱼头微信好友一块儿探讨,固然,鱼头也很是但愿能跟你一块儿聊生活,聊爱好,谈天说地。 鱼头的微信号是:krisChans95 也能够扫码关注公众号,订阅更多精彩内容。