一个面试题

来源:3-10 vue组件更新之后如何获取最新DOM

光天化日之下

2020-03-10

<div id="outer" @click="fn">
  <div @click="fn" id="inner">
    click me
  </div>
</div>

methods: {
    fn() {
      console.log('start');
      setTimeout(() => {
        console.log('timeout');
      }, 0);
      this.$nextTick(() => {
        console.log('nextTick');  
        this.$nextTick(() => { console.log('nextTick2'); });
        setTimeout(() => { console.log('timeout2'); });
      });
      console.log('end');
    }
  }

点击outer的时候,执行fn的结果如下,这个我可以理解,因为nextTick是基于promise实现的,优先级高于setTimeout
start
end
nextTick
nextTick2
timeout
timeout2


但是点击inner的时候,由于冒泡会执行两次fn,结果如下:
start
end
nextTick
nextTick2
start
end
nextTick
nextTick2
timeout
timeout2
timeout
timeout2


这个我不大明白,为什么不是
先执行完同步代码,
再执行优先级高一点的nextTick,
然后再执行setTimeout
start
end
start
end
nextTick
nextTick2
nextTick
nextTick2
timeout
timeout2
timeout
timeout2

写回答

1回答

双越

2020-03-10

点击 inner ,根据事件冒泡机制,会执行两次 click 事件,即两次 fn 。DOM 事件的执行机制,其实有点类似于 setTimeout ,也是基于异步队列和 event loop 实现的。而不是用原生 js 执行了两次 fn();

这就类似于用 setTimeout 触发了两次 fn

setTimeout(fn);
setTimeout(fn);

如果这么考虑,是不是就跟答案一样了?

2
5
THEEND0123
回复
双越
老师,是因为primise是微任务,Promise(它只是异步管理工具,并不代表就是异步)中没有异步,实际这里就当作同步就行了,事件轮询机制,先执行微任务队列,再dom渲染,最后执行宏任务(setTimeout)。我理解主要是微任务之后就尝试渲染了,因此会nextTick、nextTick2就执行start、end了。老师,您看理解的对吗?
2021-02-24
共5条回复

前端框架及项目面试 聚焦Vue3/React/Webpack

面向1-3年前端的框架及项目面试“刚需内容”

4695 学习 · 1667 问题

查看课程