成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

React 并發(fā)模式到底是個啥?

開發(fā) 前端
到目前為止,React 的并發(fā)模式就只體現(xiàn)在任務(wù)優(yōu)先級和任務(wù)可被中斷上。如果單獨(dú)考慮任務(wù)可被中斷,他實(shí)現(xiàn)的效果就跟防抖、節(jié)流比較類似,概念比較高大上,但說穿了其實(shí)也沒啥用。

在計(jì)算機(jī)里,并發(fā)「concurrent」一詞,最早是用來表示多個任務(wù)同時進(jìn)行。但是由于早期的計(jì)算機(jī)能力有限,單核計(jì)算機(jī)同一時間,只能運(yùn)行一個任務(wù)。因此,為了做到看上去多個應(yīng)用是在同時運(yùn)行的,單核計(jì)算機(jī)就快速的在不同的應(yīng)用中來回切換,它執(zhí)行完 A 應(yīng)用的一個任務(wù),就執(zhí)行 B 應(yīng)用的任務(wù),只要切換得足夠快,對于用戶而言,A 應(yīng)用與 B 應(yīng)用就是在同時運(yùn)行。

因此,對于單核 CPU 來說,多個任務(wù)同時執(zhí)行這種情況并不存在。

后來的主流計(jì)算機(jī)已經(jīng)可以做到多個任務(wù)同時執(zhí)行了,但是并發(fā)一詞已經(jīng)有了自己專屬的場景,于是我們把真正的多個任務(wù)同時執(zhí)行又重新取了一個名字,并行「parallel」

而并發(fā)則保留了它原本在單核 CPU 上的的含義:多個任務(wù)切換執(zhí)行。為了知道下一個任務(wù)到底應(yīng)該是誰執(zhí)行了,那么單核 CPU 上必定會設(shè)計(jì)一個調(diào)度模式,用來確定任務(wù)的優(yōu)先級。因此,并發(fā)的另外一個角度的解讀,就是多個任務(wù)對同一執(zhí)行資源的競爭。

一、React 的并發(fā)

在頁面使用 JS 操作 DOM 渲染頁面的過程中,也是同樣的道理,他不存在有兩個任務(wù)能同時執(zhí)行的情況。不過,React 設(shè)計(jì)了一種機(jī)制,來模擬渲染資源的競爭。

首先,React 設(shè)計(jì)了一個調(diào)度器,Scheduler,來調(diào)度任務(wù)的優(yōu)先級。

但是在爭取誰更先渲染這個事情,在瀏覽器的渲染原理里,他經(jīng)不起推敲。為什么呢?因?yàn)闉g覽器的底層渲染機(jī)制有收集邏輯,他會合并所有的渲染指令

div.style.color = 'red'
div.style.backgroundColor = '#FFF'
...

多個指令,會被合并成一個渲染任務(wù)。那也就意味著,對于瀏覽器而言,不存在渲染資源的競爭,因?yàn)椴煌匿秩局噶疃紩缓喜ⅰ<热贿@樣,那 React 的并發(fā)又是怎么回事呢?

還有更詭異的事情,React 的渲染指令,是通過 setState 來觸發(fā),我們知道,多個 setState 指令,React 也會將他們合并批處理

setLoading(false)
setList([])

// 等價(jià)于
setState({
  loading: false,
  list: []
})

既然如此,并發(fā)體現(xiàn)在什么地方呢?也不存在渲染資源的競爭啊?我們看不到任務(wù)的切換執(zhí)行,也看不到不同任務(wù)對渲染資源的競爭。所以真相就是...

大多數(shù)情況下,React 確實(shí)并不存在任何并發(fā)現(xiàn)象。

而事實(shí)上,當(dāng)我們已經(jīng)明確了哪些 DOM 需要被操作,對于瀏覽器來說,他可以足夠快的渲染更新,因此,在一幀的時間里,就算合并非常多的 DOM 操作,瀏覽器也足以應(yīng)對。夠用,就表示競爭毫無意義。

只有在渲染超大量的 DOM 和大量表單時,瀏覽器的渲染引擎表示有壓力

因此,資源競爭只會發(fā)生在,渲染能力不夠用的時候。

一次渲染包括兩個部分,一個部分是 JS 邏輯,我們需要在 JS 邏輯中明確具體的 DOM 操作是什么。第二個部分是渲染引擎執(zhí)行渲染任務(wù)。很明顯,對于 React 而言,他無法改變渲染引擎的邏輯。那么也就意味著,React 的并發(fā)只會發(fā)生在第一個部分:JS 邏輯中。

因此,react 還設(shè)計(jì)了第二步驟,Reconciler。當(dāng)我們通過 setState 觸發(fā)一個渲染任務(wù)時,react 需要在 Reconciler 中,利用 diff 算法找出來哪些 DOM 需要被更改。如果多個 setState 指令合并之后,我們發(fā)現(xiàn) diff 過程超出了一幀的時間,這個時候就有可能會存在渲染資源的競爭。

Scheduler

Reconciler

Renderer

收集

diff

操作 DOM

優(yōu)先級

可中斷


但是,如果只有一幀超出的時候,這一幀之后,瀏覽器再也沒有新的渲染任務(wù),那么就算超出了也無所謂。也沒有必要去競爭渲染資源,只有一種可能,那就是短時間之內(nèi)需要多次渲染。如果每一幀的時間都超標(biāo)了,那么頁面就會卡頓。

因此,只有在短時間之內(nèi)頁面需要多次渲染,才會存在資源競爭的情況。這個時候我們才會考慮并發(fā)的存在。

我們還需要進(jìn)一步思考。剛才我們已經(jīng)分析出,只有在短時間之內(nèi)多次渲染,并且造成了頁面卡頓,我們才會考慮并發(fā)。說明此時我們想要使用并發(fā)來解決的問題就是讓頁面不卡頓。因此,在多次渲染的前提下,多個任務(wù)的競爭結(jié)果就一定是渲染任務(wù)總量減少了,才會不卡頓。所以我們要做的事情就是,找出優(yōu)先級更低的任務(wù),即使他掉幀,只要不影響頁面卡頓,我們都可以接受。

在 React 的底層設(shè)計(jì)中,setState 是一個任務(wù),但是這個任務(wù)會影響哪些 UI 發(fā)生變化,它就可能會對應(yīng)多個 Fiber,每一個 Fiber 的執(zhí)行都是一個小任務(wù),我們可以把一個任務(wù)看成一個函數(shù)。

一旦一個任務(wù)開始執(zhí)行之后,React 不具備提前判斷這個任務(wù)執(zhí)行結(jié)束需要多少時間。只有等他執(zhí)行完了,我們才能夠算出來他一共執(zhí)行了多久。因此,對于哪些 setState 是耗時較長的任務(wù),React 無法判斷,只有通過開發(fā)者自己去判斷。我們需要在觸發(fā) setState 時,就標(biāo)記這個任務(wù)的優(yōu)先級,否則 react 也判斷不了這個任務(wù)是否耗時比較長。因此,我們需要手動使用 startTransition 來標(biāo)記耗時的 setState

function TabContainer() {
  const [isPending, startTransition] = useTransition();
  const [tab, setTab] = useState('about');

  function selectTab(nextTab) {
    startTransition(() => {
      setTab(nextTab);
    });
  }
  // ……
}

另外一個問題就是,競爭是如何發(fā)生的。

通過時間切片中斷任務(wù)的執(zhí)行,給優(yōu)先級更高的任務(wù)一個插隊(duì)的機(jī)會。

例如上面例子,當(dāng)我們使用 StartTransition 標(biāo)記了 setTab 為一個耗時較長的任務(wù)時。setTab 會有許多小的 Fiber 節(jié)點(diǎn)任務(wù)組成,我們在 Reconciler 階段執(zhí)行每一個小的 Fiber 節(jié)點(diǎn)任務(wù)之前,都會判斷此時是否應(yīng)該打斷循環(huán)。

function workLoop(hasTimeRemaining, initialTime) {
  var currentTime = initialTime;
  advanceTimers(currentTime);
  currentTask = peek(taskQueue);

  while (currentTask !== null && !(enableSchedulerDebugging )) {
    if (currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())) {
      // 當(dāng)前任務(wù)尚未過期,但時間已經(jīng)到了最后期限
      break;
    }

這里的 frameInterval 的具體值為 5ms,就是一個時間分片。也就是說,在 子 Fiber 任務(wù)執(zhí)行的遍歷過程中,每大于 5ms,就會被打斷一次。這樣才有給更高優(yōu)先級任務(wù)執(zhí)行的機(jī)會。

function shouldYieldToHost() {
  var timeElapsed = getCurrentTime() - startTime;

  if (timeElapsed < frameInterval) { // 5ms
    // 主線程只被阻塞了很短時間;
    // smaller than a single frame. Don't yield yet.
    return false;
  } 
  // 主線程被阻塞的時間不可忽視
  return true;
}

這里需要注意的是,setTab 最終被中斷,是由于時間分片之內(nèi)沒有足夠的時間給他執(zhí)行每一個 Fiber 節(jié)點(diǎn)任務(wù),而并非是由更高優(yōu)先級的任務(wù)產(chǎn)生了導(dǎo)致它的中斷。優(yōu)先級只會影響隊(duì)列的排序結(jié)果。

例如,假設(shè) setTab 影響的 UI 中包含一個父級 Fiber 節(jié)點(diǎn)和 250 個子級Fiber 節(jié)點(diǎn)。如果我們對子 Fiber 節(jié)點(diǎn)增加一個 1ms 的阻塞,此時就至少有 50 個中斷間隔給優(yōu)先級更高的任務(wù)執(zhí)行。

function Item(props: { text: string }) {
  let startTime = performance.now();
  while (performance.now() - startTime < 1) {}
  console.log('text')
  return (
    <div>{props.text}</div>
  )
}

因此,在真實(shí)的渲染邏輯中,如果我的設(shè)備足夠強(qiáng)悍,執(zhí)行速度足夠快,就算是我標(biāo)記了低優(yōu)先級,也可能不會被中斷。

這里還需要注意的是,任務(wù)的最小單位是 Fiber,如果你的單個 Fiber 執(zhí)行時間過長,react 也無法拆分這個任務(wù)。這種情況下,我們應(yīng)該想辦法把執(zhí)行壓力分散到子組件中去。

二、總結(jié)

到目前為止,React 的并發(fā)模式就只體現(xiàn)在任務(wù)優(yōu)先級和任務(wù)可被中斷上。如果單獨(dú)考慮任務(wù)可被中斷,他實(shí)現(xiàn)的效果就跟防抖、節(jié)流比較類似,概念比較高大上,但說穿了其實(shí)也沒啥用。如果你不用 useTransition/useDefferedValue 的話,基本上你的任務(wù)也不會被中斷。

但是如果不考慮任務(wù)可被中斷呢,優(yōu)先級隊(duì)列其實(shí)也沒啥太大的意義。所以 react 的并發(fā)模式,從我個人主觀的角度來看的話,宣傳意義大于實(shí)際意義。

責(zé)任編輯:姜華 來源: 這波能反殺
相關(guān)推薦

2022-04-10 19:26:07

TypeScript類型語法

2021-05-11 07:30:58

JNIJavaAPI

2021-01-28 17:41:32

Github網(wǎng)站Pull Reques

2022-05-04 08:38:32

Netty網(wǎng)絡(luò)框架

2021-12-26 00:01:51

Log4Shell漏洞服務(wù)器

2024-08-26 14:23:56

2024-08-01 17:34:56

Promiseaxios請求

2021-12-16 15:11:59

Facebook天秤幣加密貨幣

2022-09-06 21:38:45

數(shù)字人數(shù)字孿生

2024-07-12 15:08:23

Python@wraps函數(shù)

2013-05-29 10:17:56

Hadoop分布式文件系統(tǒng)

2012-07-25 09:09:46

GNOME OS桌面

2024-02-26 00:00:00

人工智能序列數(shù)據(jù)機(jī)器人

2020-03-07 09:47:48

AVL樹算法場景

2020-10-29 07:03:56

Docker容器存儲

2024-02-01 20:15:37

2019-10-28 09:59:26

區(qū)塊鏈技術(shù)智能

2017-03-16 15:28:20

人工智能視覺識別

2021-09-13 13:24:22

硬盤SLC緩存技術(shù)SSD

2021-05-19 10:44:42

數(shù)據(jù)庫架構(gòu)技術(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 四色成人av永久网址 | 一区二区三区影院 | 欧美精品一区二区三区在线 | 九九九久久国产免费 | 日本午夜免费福利视频 | 精品久| 国产精品久久久久久久免费观看 | 精品国产一区二区在线 | 九九九久久国产免费 | 国产精品99久久久久久人 | 色婷婷亚洲一区二区三区 | 中文二区| 日韩高清一区 | 欧美成人a | 毛片视频网址 | 亚洲人人舔人人 | 91视频免费黄 | 欧美三级视频在线观看 | 就操在线 | 深爱激情综合 | 国产精品毛片一区二区三区 | 免费在线视频精品 | 理论片87福利理论电影 | 99热精品6 | 超碰av免费| 一区二区三区国产 | 亚洲国产精品suv | 99久久免费精品国产免费高清 | 日韩欧美不卡 | 在线观看av网站 | 色屁屁在线观看 | 欧美黄色性生活视频 | 91精品一区二区三区久久久久 | www国产成人免费观看视频,深夜成人网 | 欧美jizzhd精品欧美巨大免费 | 国产精品免费在线 | 色偷偷人人澡人人爽人人模 | 国产精品色 | 欧美日韩网站 | 日韩电影中文字幕 | 中文字幕在线观 |