- 做者:陳大魚頭
- 首發地址: 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 也能夠掃碼關注公衆號,訂閱更多精彩內容。