願不負努力,所願皆所求 --shopee入職閒敘

寫於開頭

通過前段時間的準備,筆者最近已經成功入職shopee。因此最近沒有更新內容,以後穩定下來以後會繼續進行輸出node

寫一寫入職以後作的事

入職shopee以後,導師有給到一個entry task,這個任務是實現一個事件機制。實現addEventListenerremoveEventListenerdispatchEvent這三個方法。api

要求是這個樣子的:數組

  • 兼容 W3C 的事件冒泡和事件捕獲模型(addEventListener 的 useCapture 參數)緩存

  • 每一個事件將會有一個優先級(由開發者設置,最高爲 0,數字越大則優先級越低,若未設置則默認爲 0),若同一時刻有多個事件須要被執行,則按照優先級從高到低執行;若其中多個事件優先級相同,先被定義的事件先執行微信

  • 在優先級與事件冒泡/捕獲模型衝突時,優先保證事件冒泡/捕獲的執行順序markdown

  • 須要將你的代碼寫成一個 TypeScript 模塊,引入方式和 API 請參考文檔數據結構

  • 若屢次爲同一元素綁定同一類型的同一 Listener,該事件在符合條件時只觸發一次,事件觸發優先級以最終註冊的優先級爲準。dom

加分項有個比較有意思的東西:儘量保證一幀的時間(16ms)中全部事件的執行時間之和不超過 10ms(暫時無需考慮超過 10ms 的單個事件),須要把在這一幀來不及執行的事件放到下一幀執行(依舊須要按照優先級來執行)函數

個人思路

W3C的事件模型是先捕獲後冒泡學習

對於addEventListener:

入參爲dom節點,監聽方法名,回調方法,其餘配置能夠用...opt接受。

實現思路

將註冊的事件同一處理,建立weakmap對象,數據結構以下:

{
    Dom:{
        handleName(監聽方法名):{
        // 存放處理捕獲和冒泡的數組
            bubble:[{ // 冒泡數組
                cb:()=>void // 事件觸發回調
                range:0 // 此事件優先級
                once:false // 兼容opt的once參數
            }],
            capture:[] // 捕獲數組,同上
        }
    }
}
複製代碼

方法內部還須要對原來的dom節點進行一次監聽,用來在用戶手動點擊觸發時的事件。這時候須要將此事件作一個緩存,以便在removeEventListener的時候去取消監聽

對於removeEventListener:

入參爲dom節點,監聽方法名,回調,是否採用捕獲模型(可選,默認false)

實現思路:

首先是健壯性處理,而後對weakmap對象中對應節點的對應事件作刪除處理。而後把在addEventListener的時候添加的監聽進行remove。

對於dispatchEvent:

這個方法應該算是關鍵,他的入參是dom節點和監聽方法名。

實現思路:

  • 首先進行健壯性處理,而後遞歸的將當前節點,父節點的捕獲和冒泡數組存入數組。

  • 依次對數組中的回調進行調用。

  • 10ms的實現,使用的api是requestAnimationFrame,rAF傳入一個回調,回調中能夠拿到一個time參數,time參數指示當前被 requestAnimationFrame() 排序的回調函數被觸發的時間。在同一個幀中的多個回調函數,它們每個都會接受到一個相同的時間戳,即便在計算上一個回調函數的工做負載期間已經消耗了一些時間。該時間戳是一個十進制數,單位毫秒,最小精度爲1ms(1000μs) (--來自MDN)。 再將performance.now()運行獲得的時間戳和當前的rAF回調接受到的time進行對比,若是在10ms內能夠繼續從數組中取事件進行調用。反之,則放入下一幀

  • once 的實現,若是有once參數,就對當前的對象引用置爲空對象

這裏能夠提供一下個人思路,你們也能夠本身嘗試寫一下。

// 遞歸的去將當前節點和父節點存入數組
function recurrenceFindNodeList(
  caps: callbackType[],
  bubs: callbackType[],
  node: nodeType,
  handleName: string
) {
  const parent: any = node.parentNode;
  if (eventMap.has(parent)) {
    const parentObj = eventMap.get(parent)[handleName];
    caps = [...parentObj.capture, ...caps];
    bubs = [...bubs, ...parentObj.bubble];
    recurrenceFindNodeList(caps, bubs, parent, handleName);
  }
  return [...caps, ...bubs];
}

// 對於10ms 的實現

requestAnimationFrame(handler);
function handler(time: number) {
    let taskFinishTime: number = window.performance.now();
    while (taskFinishTime - time < 10) {
      const nextTask = tasklist.shift();
      if (nextTask?.cb) {
        nextTask.cb();
      }
      taskFinishTime = window.performance.now();
    }
    if (tasklist.length > 0) {
      requestAnimationFrame(handler);
    }
  }

複製代碼

寫於最後

shopee是一個很是年輕化的公司,在這裏從技術角度說,能夠學習到不少新技術,並參加他們的項目從0到1的過程,相信在這裏的進步會很大。若是你們想了解蝦皮歡迎加我微信:zhi794855679 。

願不負努力,所願皆所求。

相關文章
相關標籤/搜索