<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          React源碼中的位運(yùn)算技巧

          共 2366字,需瀏覽 5分鐘

           ·

          2021-11-13 17:18

          大家好,我卡頌。

          這兩年有不少朋友和我吐槽React源碼,比如:

          • 調(diào)度器為什么用小頂堆這種數(shù)據(jù)結(jié)構(gòu),直接用數(shù)組不行?

          • 源碼里各種單向鏈表、環(huán)狀鏈表,直接用數(shù)組不行?

          • 源碼里各種位運(yùn)算,有必要么?

          作為業(yè)務(wù)依賴的框架,為了提升一點(diǎn)點(diǎn)運(yùn)行時(shí)性能,React從不吝惜將源碼寫的很復(fù)雜。

          在涉及狀態(tài)標(biāo)記位優(yōu)先級操作的地方大量使用了位運(yùn)算。

          本文會講解其中比較有代表性的部分。學(xué)到之后,當(dāng)遇到類似場景時(shí)露一手,你就是業(yè)務(wù)線最靚的仔。

          幾個(gè)常用位運(yùn)算

          JS中,位運(yùn)算的操作數(shù)會先轉(zhuǎn)換為Int32(32位有符號整型),執(zhí)行完位運(yùn)算Int32對應(yīng)浮點(diǎn)數(shù)。

          React中,主要用到3種位運(yùn)算符 —— 按位與、按位或、按位非。

          按位與(&)

          對于兩個(gè)二進(jìn)制操作數(shù)的每個(gè)bit,如果都為1,則結(jié)果為1,否則為0。

          舉個(gè)例子,計(jì)算3 & 2,首先將操作數(shù)轉(zhuǎn)化為Int32

          //?3對應(yīng)的?Int32
          0b000?0000?0000?0000?0000?0000?0000?0011?
          //?2對應(yīng)的?Int32
          0b000?0000?0000?0000?0000?0000?0000?0010?

          為了直觀,我們排除前面的0,只保留最后8位(實(shí)際參與計(jì)算的應(yīng)該是32位):

          ??0000?0011
          &?0000?0010
          -----------
          ??0000?0010

          所以3 & 2計(jì)算結(jié)果轉(zhuǎn)化為浮點(diǎn)數(shù)后為2。

          按位或(|)

          對于兩個(gè)二進(jìn)制操作數(shù)的每個(gè)bit,如果都為0,則結(jié)果為0,否則為1。

          計(jì)算10 | 3

          ??0000?1010
          |?0000?0011
          -----------
          ??0000?1011

          計(jì)算結(jié)果轉(zhuǎn)化為浮點(diǎn)數(shù)后為11。

          按位非(~)

          對一個(gè)二進(jìn)制操作數(shù)的每個(gè)bit,逐位進(jìn)行取反操作(0、1互換)

          對于~3,將3轉(zhuǎn)化為Int32后逐位取反:

          //?3對應(yīng)的?Int32
          0b000?0000?0000?0000?0000?0000?0000?0011?
          //?逐位取反
          0b111?1111?1111?1111?1111?1111?1111?1100

          計(jì)算結(jié)果轉(zhuǎn)化為浮點(diǎn)數(shù)后為-4。

          如果你對這個(gè)結(jié)果有疑惑,可以去了解補(bǔ)碼相關(guān)知識

          讓我們從易到難,看看位運(yùn)算在React中的應(yīng)用。

          標(biāo)記狀態(tài)

          React源碼內(nèi)部有多個(gè)上下文環(huán)境,在執(zhí)行函數(shù)時(shí)經(jīng)常需要判斷當(dāng)前處在哪個(gè)上下文環(huán)境中。

          假設(shè)共有三種上下文情況:

          //?A上下文
          const?A?=?1;
          //?B上下文
          const?B?=?2;
          //?沒有處在上下文
          const?NoContext?=?0;

          當(dāng)進(jìn)入某個(gè)上下文時(shí),可以使用按位或操作標(biāo)記進(jìn)入:

          //?當(dāng)前所處上下文
          let?curContext?=?0;

          //?進(jìn)入A上下文
          curContext?|=?A;

          我們用8位二進(jìn)制舉例(同樣,實(shí)際應(yīng)該是Int32,這里是為了簡化),curContextA執(zhí)行按位或操作:

          ??0000?0000??//?curContext
          |?0000?0001??//?A
          -----------
          ??0000?0001

          此時(shí)可以結(jié)合按位與操作與NoContext來判斷是否處在某一上下文中:

          //?是否處在A上下文中?true
          (curContext?&?A)?!==?NoContext

          //?是否處在B上下文中?false
          (curContext?&?B)?!==?NoContext

          離開某上下文后,結(jié)合按位與按位非移除標(biāo)記:

          //?從當(dāng)前上下文中移除上下文A
          curContext?&=?~A;

          //?是否處在A上下文中?false
          (curContext?&?A)?!==?NoContext

          curContext~A執(zhí)行按位與操作:

          ??0000?0001??//?curContext
          &?1111?1110??//?~A
          -----------
          ??0000?0000

          即從curContext中移除A

          當(dāng)業(yè)務(wù)中需要同時(shí)處理多個(gè)狀態(tài)時(shí),可以使用如上位運(yùn)算技巧。

          優(yōu)先級計(jì)算

          React中,不同情況下調(diào)用this.setState觸發(fā)的更新會擁有不同優(yōu)先級。優(yōu)先級之間的比較、挑選同樣使用了位運(yùn)算。

          具體來說,React中用31個(gè)bit位保存「更新」(之所以是31而不是32是因?yàn)?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;">Int32的最高位是符號位,不保存具體的數(shù))。

          處在越低bit位的更新優(yōu)先級越高(越需要優(yōu)先處理)。

          舉個(gè)例子,假設(shè)當(dāng)前應(yīng)用存在2個(gè)更新:

          0b000?0000?0000?0000?0000?0000?0001?0001

          其中第1位的更新優(yōu)先級最高(需要同步處理),第5位為默認(rèn)優(yōu)先級。

          React經(jīng)常需要找出當(dāng)前最高優(yōu)先級的更新在哪一位(如上例子中在第一位),方法如下:

          function?getHighestPriorityLane(lanes)?{
          ??return?lanes?&?-lanes;
          }

          解釋下,由于Int32采用「補(bǔ)碼」表示,所以-lanes可以看作如下兩步操作:

          1. lanes取反(~lanes)

          2. 加1

          為了直觀,用8位表示:

          lanes??0001?0001
          ~lanes?1110?1110?//?第一步
          +1?????1110?1111?//?第二步

          lanes & -lanes如下:

          ??0001?0001?//?lanes??
          &?1110?1111?//?-lanes
          -----------
          ??0000?0001

          取到的就是第一位(已有更新中最高的優(yōu)先級)。

          總結(jié)

          雖然業(yè)務(wù)中不常使用位操作,但在特定場景下位操作時(shí)很方便、高效的方式。

          這波操作你愛了么?


          「分享」「點(diǎn)贊」「在看」是最大支持
          瀏覽 37
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美特黄一区二区三区 | 欧美A片在线视频 | 超碰免费网站 | 无码视频免费播放 | 亚洲大胆人体视频 |