Skip to content

Latest commit

 

History

History
276 lines (156 loc) · 9.63 KB

20210528.md

File metadata and controls

276 lines (156 loc) · 9.63 KB

2021-05-28 技术周刊

文章精读

Chrome 89 更新事件触发顺序,导致99%的文章都错了(包括MDN)

from -- 点我

先来做道题吧(bushi)

<div>
  <button>123</button>
</div>

<script>
  var div = document.querySelector('div');
  var btn = document.querySelector('button');

  btn.addEventListener('click', function() {
    console.log('bubble', 'btn');
  }, false);

  btn.addEventListener('click', function() {
    console.log('capture', 'btn');
  }, true);

  div.addEventListener('click', function() {
    console.log('bubble', 'div');
  }, false);

  div.addEventListener('click', function() {
    console.log('capture', 'div');
  }, true);

</script>

先不看结果,思考一下。

图片

capture div
bubble btn
capture btn
bubble div

非也非也!

图片

看看同行怎么说~

  • csdn

图片

  • 掘金

图片

  • MDN 你这浓眉大眼的呢?

    图片
  • 老版本 chrome~呢?

图片

于是作者决定给 chromium 报 bug~

图片

最终在 Chrome 开发人员的帮助下,找到了这两个讨论

whatwg/dom#685

图片

whatwg/dom#746

图片

起因是在 https://bugs.webkit.org/show_bug.cgi?id=174288 中,有人指出,在 webkit 中当前的事件模型,会导致含有 Shadow DOM 的情况下,子元素的捕获事件会优先于父元素的捕获事件触发。

图片

而在旧模型中,一旦达到 AT_TARGET ,所有注册的监听器就将按照顺序被触发,而不管他们是否被标记为捕获。由于 Shadow DOM 会创建多个 targets ,导致了事件执行顺序的错误。

而上述问题在 Gecko (Mozilla Firefox 的排版引擎)却运行正常(先捕获再冒泡)。为此 whatwg 提出了一个新的模型结构来解决这个问题。

图片

总结

1.按照旧版本事件触发机制
表现 目标元素触发事件顺序和注册事件顺序有关
2.新的的事件触发机制
表现 目标元素触发事件顺序按照先捕获再冒泡的顺序触发

而这个版本分界线是在 Chrome 89.0.4363.089.0.4358.0

在 Chrome 89.0.4363.0 以及之后版本中,目标元素的触发事件顺序不再按照注册顺序触发而是按照先捕获再冒泡的形式依次执行!

可能引发的线上 bug 解决方案

我们只需要将所有目标元素代码的顺序都按照先书写捕获事件代码,再书写冒泡事件代码,就可以兼容本次的更新。

思考

所有的事情都不是一成不变的,不管是对于一些相对官方的文章或者教程我们都要抱以怀疑的态度,相信我们所看到的。也许我这篇的言论在多年之后也会是一个错误示例,但是是对当下问题的一个记录。本文也还有很多不足之处,如果有问题请在评论中指出。

这文章让我想起之前碰到过类似的异步执行顺序问题。

async function async1(){
  await async2()
  console.log('async1 end')
}
async function async2(){}

async1();

new Promise(function(resolve){
  resolve();
}).then(function(){
  console.log('promise2')
}).then(function() {
  console.log('promise3')
}).then(function() {
  console.log('promise4')
})

在 chrome canary 73 返回

async1 end
promise2
promise3
promise4

而在 chrome 70 上返回

promise2
promise3
async1 end
promise4

这道题其实问的是

await async2() 怎么理解?

因为 async 函数总是返回一个 promise,所以其实就是在问

await promise 怎么理解?

在此不深究,有兴趣的话可以查阅以下参考资料~

新闻、文章、工具

视频 + PPT 放出!

Webpack无疑是目前最受欢迎的前端项目的打包和构建工具,目前也达到了第五个大版本,包含了非常多的功能。

然而,在以下场景中,Webpack已经不是最好的打包构建工具:

  • Dev模式下的构建速度
  • 非常简单的配置文件
  • Bundle文件大小

针对上述几个问题,社区有一些其他可使用的替换工具,如ParcelRollupViteSnowpack等。

所以,在以后的项目构建技术方案选型时,可以多考虑一下你的使用场景,是否真的应该还使用Webpack?

文中介绍了关于img标签相关的两个东西:alt属性和figcaption标签。

alt属性,大家应该都不陌生,它是图片资源的一个描述信息,且只在图片加载失败的情况下才会显示出来,以应对这些异常情况和支持Accessibility的场景(它的内容会被阅读器读出来)。

figcaption标签不太一样,它也是表示对图片内容的描述,只不过它需要被figure标签包裹,且内容会一直显示页面中。文中给出了一些这两个特性的使用场景介绍和示例代码,可以帮助你更好地理解它们。

我们现在在网上(尤其是中文搜索环境中)获取到的关于活跃对象和可变对象(Variable Object)的文章,大多都是为我们描述的 ECMAScript 1 和 3,早已过时。

在 ES5 及之后的 ES 版本,已经不存在活跃对象(AO)及一系列周边内容的概念了。取而代之,是一个叫词法环境(Lexical Environments)的定义。

我们现在再聊起活跃对象时,应该知道它只是广义的抽象,而不再是狭义的定义了。广义的活跃对象在不同的场景下也可以有不同的名字,如活跃记录(Activation Record)、栈帧(Stack Frame)等。

zx是一个JavaScript生态下的工具,它可以让你通过JavaScript调用并执行bash命令,用法还比较简单直观。

#!/usr/bin/env zx

await $`cat package.json | grep name`

let branch = await $`git branch --show-current`
await $`dep deploy --branch=${branch}`

await Promise.all([
  $`sleep 1; echo 1`,
  $`sleep 2; echo 2`,
  $`sleep 3; echo 3`,
])

let name = 'foo bar'
await $`mkdir /tmp/${name}`

超简单判断闰年

通常我们要判断某一年是否是闰年,需要掌握闰年的定义规则,并按照该负责的规则来判断。下面介绍一个通过反推来判断是否是闰年的方法。

function isLeapYear(year: number) {
  return new Date(year, 1, 29).getDate() === 29
}

export default isLeapYear