亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題

發布時間:2022-08-13 15:19:51 來源:億速云 閱讀:357 作者:iii 欄目:開發技術

這篇文章主要講解了“怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題”吧!

    起因

    同事遇到一個動畫展示的問題,就是下面要執行一個運算量很大的函數,他要加載一個 loading,但他發現把 loading 的元素 display: block; 頁面中也不會立刻出現 loading 動畫,出現動畫的時候是運算函數執行完畢之后。

    處理辦法

    有兩種方法去處理這種耗時任務,第一種就是 webWorker,但是一些 dom 的操作做不了,于是就想到了通過 generator 函數來解決,下面先簡單了解下事件循環。

    事件循環

    怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題

    微任務:

    1. Promise.then

    2. Object.observe

    3. MutaionObserver

    宏任務:

    1. script(整體代碼)

    2. setTimeout

    3. setInterval

    4. I/O

    5. postMessage

    6. MessageChannel

    瀏覽器渲染時機

    除去特殊情況,頁面的渲染會在微任務隊列清空后,宏任務執行前,所以我們可以讓推入主執行棧的函數執行到一定時間就去休眠,然后在渲染之后的宏任務里面叫醒他,這樣渲染或者用戶交互都不會卡頓了!

    原始代碼

    我們先模擬一個 js 長任務

    代碼
    // style
    @keyframes move {
        from {
            left: 0;
        }
        to {
            left: 100%;
        }
    }
    .move {
        position: absolute;
        animation: move 5s linear infinite;
    }
    // dom
    <div class="move">123123123</div>
    // script
    function fnc () {
        let i = 0
        const start = performance.now()
        while (performance.now() - start <= 5000) {
            i++
        }
        return i
    }
    setTimeout(() => {
        fnc()
    }, 1000)
    效果
    動畫運行 1s 的時候,js 函數開始運行,動畫會先停止渲染,然后等 js 主執行棧空閑之后動畫才繼續進行。

    怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題

    函數改造

    我們把原來的函數改造為 generator 函數

    代碼
    // generator 處理原來的函數
    function * fnc_ () {
        let i = 0
        const start = performance.now()
        while (performance.now() - start <= 5000) {
            yield i++
        }
        return i
    }
    // 簡易時間分片
    function timeSlice (fnc, cb = setTimeout) {
        if(fnc.constructor.name !== 'GeneratorFunction') return fnc()
        return async function (...args) {
            const fnc_ = fnc(...args)
            let data
            do {
                data = fnc_.next(await data?.value)
                // 每執行一步就休眠,注冊一個宏任務 setTimeout 來叫醒他
                await new Promise( resolve => cb(resolve))
            } while (!data.done)
            return data.value
        }
    }
    setTimeout(async () => {
        const fnc = timeSlice(fnc_)
        const start = performance.now()
        console.log('開始')
        const num = await fnc()
        console.log('結束', `${(performance.now() - start)/ 1000}s`)
        console.log(num)
    }, 1000)
    效果

    動畫根本不受影響,fps 一直很穩定,因為我們把耗時任務拆成很多個塊來執行。

    怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題

    優化時間分片

    上面的時間分片函數每執行一步,就會休眠,然后通過一個宏任務來喚醒他,但是這樣的執行效率肯定是比較低的,我們再優化一下執行的效率,提升連續執行時間。

    代碼
    // 精準時間分片
    function timeSlice_ (fnc, time = 25, cb = setTimeout) {
        if(fnc.constructor.name !== 'GeneratorFunction') return fnc()
        return function (...args) {
            const fnc_ = fnc(...args)
            let data
            return new Promise(async function go (resolve, reject) {
                try {
                    const start = performance.now()
                    do {
                        data = fnc_.next(await data?.value)
                    } while (!data.done && performance.now() - start < time)
                    if (data.done) return resolve(data.value)
                    cb(() => go(resolve, reject))
                } catch(e) {
                    reject(e)
                }
            })
        }
    }
    setTimeout(async () => {
        const fnc1 = timeSlice_(fnc_)
        let start = performance.now()
        console.log('開始')
        const num = await fnc1()
        console.log('結束', `${(performance.now() - start)/ 1000}s`)
        console.log(num)
    }, 1000);
    效果

    我們把函數分成了較大的塊,這樣函數執行的效率就會變高,fps 會稍微收到影響,但是在接受范圍內。

    怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題

    對比優化前后

    我們對比一下優化時間分片函數前后的效果

    代碼
    setTimeout(async () => {
        const fnc = timeSlice(fnc_)
        const fnc1 = timeSlice_(fnc_)
        let start = performance.now()
        console.log('開始')
        const a = await fnc()
        console.log('結束', `${(performance.now() - start)/ 1000}s`)
        console.log('開始')
        start = performance.now()
        const b = await fnc1()
        console.log('結束', `${(performance.now() - start)/ 1000}s`)
        console.log(a, b)
    }, 1000);
    效果

    對比優化后的時間分片函數,是之前效率的 4452 倍,我們做的只是提升了函數連續執行時間。

    怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題

    感謝各位的閱讀,以上就是“怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題”的內容了,經過本文的學習后,相信大家對怎么使用JS時間分片技術解決長任務導致的頁面卡頓問題這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    js
    AI

    九龙县| 南京市| 西充县| 庐江县| 准格尔旗| 三河市| 石门县| 长治市| 苍溪县| 英超| 蓬莱市| 新兴县| 白山市| 大洼县| 康马县| 新乡县| 韩城市| 望奎县| 南乐县| 洛南县| 白沙| 彰武县| 册亨县| 东乡族自治县| 邛崃市| 绿春县| 思南县| 边坝县| 宜兰县| 大化| 青海省| 洛扎县| 惠东县| 陵水| 香格里拉县| 正定县| 宕昌县| 通海县| 张家界市| 新田县| 调兵山市|