国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

再談?wù)?Promise, setTimeout, rAF, rIC

jasperyang / 3047人閱讀

摘要:二事件循環(huán)與幀事件循環(huán)和上面?zhèn)€名詞的基本概念在此不再啰嗦了,我們著重看下它們之間的關(guān)系。瀏覽器是一個(gè)系統(tǒng),所有的操作最終都會(huì)以頁(yè)面的形式展現(xiàn),而頁(yè)面的基本單位是幀。當(dāng)某一幀的任務(wù)占用大量時(shí)間的時(shí)候,會(huì)影響到下一幀的執(zhí)行。

歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:

一、前言

Promise, setTimeout, requestAnimationFrame, requestIdleCallback 這幾個(gè)概念相信很多人都很熟悉了,最近在看 React Fiber 源碼的時(shí)候又對(duì)它們有了更深一層的認(rèn)識(shí),在此分享一下。下文將用 rAF 代表 requestAnimationFrame, rIC 代表 requestIdleCallback

二、事件循環(huán)與幀

事件循環(huán)和上面 4 個(gè)名詞的基本概念在此不再啰嗦了,我們著重看下它們之間的關(guān)系。瀏覽器是一個(gè) UI 系統(tǒng),所有的操作最終都會(huì)以頁(yè)面的形式展現(xiàn),而頁(yè)面的基本單位是幀。一幀中可能包括的任務(wù)有下面幾種類型。

events: 點(diǎn)擊事件、鍵盤事件、滾動(dòng)事件等

macro: 宏任務(wù),如 setTimeout

micro: 微任務(wù),如 Promise

rAF: requestAnimationFrame

Layout: CSS 計(jì)算,頁(yè)面布局

Paint: 頁(yè)面繪制

rIC: requestIdleCallback

理想情況下,頁(yè)面會(huì)以 60 幀每秒的幀率來(lái)運(yùn)行,但實(shí)際上每秒繪制多少幀是由多個(gè)因素決定的,下面舉一些例子:

一個(gè)加載完成的靜態(tài)頁(yè)面,當(dāng)用戶沒(méi)有進(jìn)行交互的情況下,頁(yè)面不需要重繪,幀率為 0。

快速滾動(dòng)頁(yè)面的時(shí)候,可視區(qū)域的內(nèi)容不斷發(fā)生變化,瀏覽器會(huì)盡可能快的重繪頁(yè)面,理想幀率為 60。

假設(shè)頁(yè)面有一個(gè)注冊(cè)了回調(diào)的按鈕,回調(diào)執(zhí)行需要 500 毫秒。當(dāng)點(diǎn)擊按鈕后再快速滾動(dòng)頁(yè)面,頭 500 毫秒頁(yè)面是卡住動(dòng)不了的,后 500 毫秒會(huì)盡可能快的重繪頁(yè)面,這時(shí)候理想幀率為 30。

當(dāng)使用 rAF 制作動(dòng)畫的時(shí)候,瀏覽器會(huì)盡可能快的重繪頁(yè)面,桌面瀏覽器可能是 60 幀,移動(dòng)瀏覽器可能是 30 幀。

從上面的例子可以看出,頁(yè)面的幀率不是固定的,是會(huì)動(dòng)態(tài)變化的。當(dāng)某一幀的任務(wù)占用大量時(shí)間的時(shí)候,會(huì)影響到下一幀的執(zhí)行。那么誰(shuí)來(lái)調(diào)節(jié)幀率呢?顯然只能依靠瀏覽器自身。作為開發(fā)者的我們是無(wú)法準(zhǔn)確預(yù)知回調(diào)什么時(shí)候執(zhí)行的。比如:

function animation() {
   console.log("time: ", +new Date());
   setTimeout(animate, 1000 / 60);
}

animation();

上面的函數(shù)假定了瀏覽器以幀率 60 來(lái)運(yùn)行,但當(dāng)幀率達(dá)不到的時(shí)候,2 幀之間回調(diào)可能執(zhí)行了多次,也可能一次都不執(zhí)行,簡(jiǎn)稱掉幀。

所以在制作動(dòng)畫的時(shí)候,我們不能預(yù)設(shè)瀏覽器的幀率,正確的做法是通過(guò) rAF 注冊(cè)回調(diào), 由瀏覽器來(lái)控制動(dòng)畫調(diào)用時(shí)機(jī):

function animation() {
   console.log("time: ", +new Date());
   requestAnimationFrame(animation);
}

animation();

rAF 會(huì)保證注冊(cè)的回調(diào)在下次渲染頁(yè)面之前執(zhí)行,且只會(huì)執(zhí)行一次。另外,當(dāng)頁(yè)面處于不可見狀態(tài)時(shí),rAF 會(huì)自動(dòng)停止執(zhí)行,以節(jié)省系統(tǒng)資源。

三、執(zhí)行順序

Promise, setTimeout , rAFrIC 對(duì)應(yīng) 4 種隊(duì)列:微任務(wù)隊(duì)列、宏任務(wù)隊(duì)列、animation 隊(duì)列和 idle 隊(duì)列。

微任務(wù)隊(duì)列會(huì)在 JS 運(yùn)行棧為空的時(shí)候立即執(zhí)行。

animation 隊(duì)列會(huì)在頁(yè)面渲染前執(zhí)行。

宏任務(wù)隊(duì)列優(yōu)先級(jí)低于微任務(wù)隊(duì)列,一般也會(huì)比 animation 隊(duì)列優(yōu)先級(jí)低,但不是絕對(duì) 。

idle 隊(duì)列優(yōu)先級(jí)最低,當(dāng)瀏覽器有空閑時(shí)間的時(shí)候才會(huì)執(zhí)行。

setTimeout(()=>console.log("setTimeout"), 0);
Promise.resolve().then(()=>console.log("promise"));
requestAnimationFrame(()=>console.log("animation"));
requestIdleCallback(()=>console.log("idle"));

// 執(zhí)行結(jié)果大多數(shù)情況下是: promise, animation, setTimeout, idle
// 少數(shù)情況是:promise, setTimeout, animation, idle

再來(lái)談?wù)効臻e時(shí)間怎么理解。假設(shè)在 1 秒內(nèi)有 3 幀需要渲染:

第一幀,由于宏任務(wù)占用了大量的時(shí)間,沒(méi)有空閑時(shí)間。

第二幀,rAF占用的時(shí)間不多,有大量的空閑時(shí)間

第三幀,瀏覽器事件占用的時(shí)間不多,有大量的空閑時(shí)間

rAF類似,rIC 的執(zhí)行時(shí)機(jī)是由瀏覽器控制的,能更好的保證體驗(yàn),優(yōu)化性能。一般優(yōu)先級(jí)高的任務(wù)(如 UI 更新)會(huì)放在 rAF 隊(duì)列,優(yōu)先級(jí)低的任務(wù)(如日志上傳)會(huì)放 rIC

四、隊(duì)列特性

在一個(gè)事件循環(huán)內(nèi),各個(gè)隊(duì)列有以下特性:

宏任務(wù)隊(duì)列,每次只會(huì)執(zhí)行隊(duì)列內(nèi)的一個(gè)任務(wù)。

微任務(wù)隊(duì)列,每次會(huì)執(zhí)行隊(duì)列里的全部任務(wù)。假設(shè)微任務(wù)隊(duì)列內(nèi)有 100 個(gè) Promise,它們會(huì)一次過(guò)全部執(zhí)行完。這種情況下極有可能會(huì)導(dǎo)致頁(yè)面卡頓。如果在微任務(wù)執(zhí)行過(guò)程中繼續(xù)往微任務(wù)隊(duì)列中添加任務(wù),新添加的任務(wù)也會(huì)在當(dāng)前事件循環(huán)中執(zhí)行,很容易造成死循環(huán), 如:

function loop() {
    Promise.resolve().then(loop);
}

loop();

animation 隊(duì)列,跟微任務(wù)隊(duì)列有點(diǎn)相似,每次會(huì)執(zhí)行隊(duì)列里的全部任務(wù)。但如果在執(zhí)行過(guò)程中往隊(duì)列中添加新的任務(wù),新的任務(wù)不會(huì)在當(dāng)前事件循環(huán)中執(zhí)行,而是在下次事件循環(huán)中執(zhí)行。

idle 隊(duì)列,每次只會(huì)執(zhí)行一個(gè)任務(wù)。任務(wù)完成后會(huì)檢查是否還有空閑時(shí)間,有的話會(huì)繼續(xù)執(zhí)行下一個(gè)任務(wù),沒(méi)有則等到下次有空閑時(shí)間再執(zhí)行。需要注意的是此隊(duì)列中的任務(wù)也有可能阻塞頁(yè)面,當(dāng)空閑時(shí)間用完后任務(wù)不會(huì)主動(dòng)退出。如果任務(wù)占用時(shí)間較長(zhǎng),一般會(huì)將任務(wù)拆分成多個(gè)階段,執(zhí)行完一個(gè)階段后檢查還有沒(méi)有空閑時(shí)間,有則繼續(xù),無(wú)則注冊(cè)一個(gè)新的 idle 隊(duì)列任務(wù),然后退出當(dāng)前任務(wù)。React Fiber 就是用這個(gè)機(jī)制。但最新版的 React Fiber 已經(jīng)不用 rIC 了,因?yàn)檎{(diào)用的頻率太低,改用 rAF

五、總結(jié)

本文介紹了 4 種隊(duì)列的執(zhí)行順序和每個(gè)隊(duì)列的特性,它們是:宏任務(wù)隊(duì)列、微任務(wù)隊(duì)列、animation 隊(duì)列和 idle 隊(duì)列。實(shí)際應(yīng)用時(shí)可以根據(jù)它們各自的特點(diǎn)分配不同的任務(wù)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/109452.html

相關(guān)文章

  • promise、process.nextTick、setTimeout出發(fā),談?wù)?/em>Event Loo

    摘要:比如下面一個(gè)例子例輸出為先輸出,沒(méi)有問(wèn)題,因?yàn)槭峭饺蝿?wù)在主線程中優(yōu)先執(zhí)行,這里的問(wèn)題是和任務(wù)的執(zhí)行優(yōu)先級(jí)是如何定義的。 在原文的基礎(chǔ)上加了一點(diǎn)參考資料 問(wèn)題的引出 event loop都不陌生,是指主線程從任務(wù)隊(duì)列中循環(huán)讀取任務(wù),比如 例1: setTimeout(function(){console.log(1)},0); console.log(2) //輸出2,1 在上述...

    zero 評(píng)論0 收藏0
  • 談?wù)?/em>ES6前后的異步編程

    摘要:回調(diào)函數(shù)這是異步編程最基本的方法。對(duì)象對(duì)象是工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口。誕生后,出現(xiàn)了函數(shù),它將異步編程帶入了一個(gè)全新的階段。 更多詳情點(diǎn)擊http://blog.zhangbing.club/Ja... Javascript 語(yǔ)言的執(zhí)行環(huán)境是單線程的,如果沒(méi)有異步編程,根本沒(méi)法用,非卡死不可。 為了解決這個(gè)問(wèn)題,Javascript語(yǔ)言將任務(wù)的執(zhí)行模式分成兩種...

    fizz 評(píng)論0 收藏0
  • 談?wù)?/em> ES6 的 Promise 對(duì)象

    摘要:一般會(huì)這樣去寫要在第一個(gè)請(qǐng)求成功后才可以執(zhí)行下一步這樣的寫法的原理是,當(dāng)執(zhí)行一些異步操作時(shí),我們需要知道操作是否已經(jīng)完成,所有當(dāng)執(zhí)行完成的時(shí)候會(huì)返回一個(gè)回調(diào)函數(shù),表示操作已經(jīng)完成。 前言 開篇首先設(shè)想一個(gè)日常開發(fā)常常會(huì)遇到的需求:在多個(gè)接口異步請(qǐng)求數(shù)據(jù),然后利用這些數(shù)據(jù)來(lái)進(jìn)行一系列的操作。一般會(huì)這樣去寫: $.ajax({ url: ......, success: f...

    linkin 評(píng)論0 收藏0
  • 瀏覽器和Node中的事件循環(huán)機(jī)制

    摘要:二瀏覽器端在講解事件循環(huán)之前先談?wù)勚型酱a異步代碼的執(zhí)行流程。三端我自己認(rèn)為的事件循環(huán)和瀏覽器端還是有點(diǎn)區(qū)別的,它的事件循環(huán)依靠引擎。四總結(jié)本篇主要介紹了瀏覽器和對(duì)于事件循環(huán)機(jī)制實(shí)現(xiàn),由于能力水平有限,其中可能有誤之處歡迎指出。 一、前言 前幾天聽公司一個(gè)公司三年的前端說(shuō)今天又學(xué)到了一個(gè)知識(shí)點(diǎn)-微任務(wù)、宏任務(wù),我問(wèn)他這是什么東西,由于在吃飯他淺淺的說(shuō)了下,當(dāng)時(shí)沒(méi)太理解就私下學(xué)習(xí)整理一...

    KevinYan 評(píng)論0 收藏0
  • 談?wù)?/em>JavaScript異步代碼優(yōu)化

    摘要:異步問(wèn)題回調(diào)地獄首先,我們來(lái)看下異步編程中最常見的一種問(wèn)題,便是回調(diào)地獄。同時(shí)使用也是異步編程最基礎(chǔ)和核心的一種解決思路。基于,目前也被廣泛運(yùn)用,其是異步編程的一種解決方案,比傳統(tǒng)的回調(diào)函數(shù)解決方案更合理和強(qiáng)大。 關(guān)于 微信公眾號(hào):前端呼啦圈(Love-FED) 我的博客:勞卜的博客 知乎專欄:前端呼啦圈 前言 在實(shí)際編碼中,我們經(jīng)常會(huì)遇到Javascript代碼異步執(zhí)行的場(chǎng)景...

    chnmagnus 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<