愿不负努力,所愿皆所求|愿不负努力,所愿皆所求 --shopee入职闲叙
写于开头
【愿不负努力,所愿皆所求|愿不负努力,所愿皆所求 --shopee入职闲叙】经过前段时间的准备,笔者最近已经成功入职shopee。所以最近没有更新内容,之后稳定下来之后会继续进行输出
写一写入职之后做的事
入职shopee之后,导师有给到一个entry task,这个任务是实现一个事件机制。实现addEventListener
,removeEventListener
,dispatchEvent
这三个方法。
要求是这个样子的:
- 兼容 W3C 的事件冒泡和事件捕获模型(addEventListener 的 useCapture 参数)
- 每个事件将会有一个优先级(由开发者设置,最高为 0,数字越大则优先级越低,若未设置则默认为 0),若同一时刻有多个事件需要被执行,则按照优先级从高到低执行;若其中多个事件优先级相同,先被定义的事件先执行
- 在优先级与事件冒泡/捕获模型冲突时,优先保证事件冒泡/捕获的执行顺序
- 需要将你的代码写成一个 TypeScript 模块,引入方式和 API 请参考文档
- 若多次为同一元素绑定同一类型的同一 Listener,该事件在符合条件时只触发一次,事件触发优先级以最终注册的优先级为准。
尽可能保证一帧的时间(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 。
愿不负努力,所愿皆所求。
推荐阅读
- 牛人进化+|牛人进化+ 按自己的意愿过一生
- 继续努力,自主学习家庭Day135(20181015)
- 是你,情愿
- 你再这样提问,就没人愿意回答你了
- 2018-07-27读书心得
- 基于爱,才会有“愿望”当“要求”。2017.8.12
- 【诗】我愿我愿
- 越努力越幸福
- 未来不可期,但愿你无悔
- 唯有努力才能拥有更好的人生