Written in the beginning

After a period of preparation, the author has successfully joined Shopee recently. Therefore, the content has not been updated recently, and the output will continue after it stabilizes

Write about what you have done since you started your career

After I joined Shopee, my mentor gave me an entry task, which was to realize an event mechanism. Implement addEventListener, removeEventListener, dispatchEvent these three methods.

The requirements look like this:

  • W3C compliant event bubble and event capture model (useCapture parameter for addEventListener)

  • Each event will have a priority (set by the developer, the highest is 0, the higher the number, the lower the priority, if not set to the default 0). If multiple events need to be executed at the same time, the event will be executed according to the priority from high to low. If multiple events have the same priority, the first defined event is executed first

  • When priorities conflict with the event bubble/capture model, the order of event bubble/capture execution is guaranteed first

  • To write your code as a TypeScript module, refer to the documentation for introduction and API

  • If the same Listener of the same type is bound to the same element for multiple times, the event is triggered only once when the conditions are met. The event trigger priority is determined by the registered priority.

There is an interesting thing about the bonus: try to ensure that the sum of execution time of all events in one frame (16ms) does not exceed 10ms (no need to consider single events over 10ms for the time being), and the events that cannot be executed in this frame should be executed in the next frame (still need to be executed according to the priority).

My train of thought

The W3C event model is capture first and bubble later

For addEventListener:

The input arguments are DOM nodes, listening method names, callback methods, and other configurations can be made using… Opt to accept.

Implementation idea:

The registered events are processed in the same way to create a WeakMap object, with the data structure as follows:

{Dom:{handleName(listener name):{// Handle the capture and bubble array bubble:[{// bubble array cb:()=>void // event trigger callback range:0 // this event priority once:false // }], capture:[] // capture array, same as above}}}Copy the code

The method also needs to have a listener inside the original DOM node for the event when the user manually clicks it. This event needs to be cached so that the listener can be removed at removeEventListener time

For the removeEventListener:

Take dom node as input, listen for method name, callback, capture model or not (optional, default false)

Implementation idea:

The first is robustness processing, and then delete the corresponding events of the corresponding nodes in the WeakMap object. Then remove the listener added during addEventListener.

For the dispatchEvent:

This method should be the key, and its input is the DOM node and the name of the listening method.

Implementation idea:

  • Robustness is first performed, and then the current node, the parent node’s capture, and the bubbling array are recursively stored into the array.

  • The callbacks in the array are called in turn.

  • RequestAnimationFrame (); rAF passes in a callback that takes a time parameter. The time parameter indicates when the callback function that is currently sorted by requestAnimationFrame() will be fired. Multiple callback functions in the same frame will each receive the same timestamp, even if some time has elapsed during the calculation of the workload for the previous callback function. The timestamp is a decimal number in milliseconds with a minimum accuracy of 1ms(1000μs) (– from MDN). Then compare the timestamp obtained by the performance.now() run with the time received by the current rAF callback, if the event can continue to be called from the array within 10ms. Otherwise, it goes to the next frame

  • The once implementation sets the current object reference to an empty object if it has the once argument

Here can provide my ideas, you can also try to write their own.

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]; } // For 10ms implementation 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); }}Copy the code

Written in the last

Shopee is a very young company. From the technical point of view, we can learn a lot of new technologies here and participate in the process from 0 to 1 of their projects. I believe there will be great progress here. If you want to know about shrimps, please add me on wechat: ZHI794855679.

May not work hard, want all you want.