共计 1501 个字符,预计需要花费 4 分钟才能阅读完成。
发现问题
在学习《Vue.js 设计与实现》渲染器局部的时候,发现在调用渲染函数之后批改虚构 DOM 的值,渲染函数中拿到的是新的虚构 DOM。
const vnode = {
type: "div",
children: [
{
type: "p",
children: "text",
},
],
};
const app = document.querySelector("#app");
renderer.render(vnode, app);
vnode.children = [
{
type: "input",
props: {value: "请输出关键字",},
},
];
- 在渲染函数中打印虚构 DOM 的值,发现后果为
把批改虚构 DOM 的代码放入 setTimeout 函数中
setTimeout(() => {
vnode.children = [
{
type: "input",
props: {value: "请输出关键字",},
},
];
});
发现打印后果没有扭转依然是批改后的虚构 DOM。
再将 setTimeout 的回调工夫批改为 2000 ms,才失去了我想要的后果。
由此揣测,渲染函数中存在有导致异步操作的代码。
定位问题
依据渲染流程,在代码中找到了可能导致异步的代码:
- document.createElement(localName, options);
- insertBefore(node, child)
接着去 Dom Standard 中查找这两个办法的具体定义:
在 createElement 的第六步中返回了 creating an element 的后果
于是去查看 creating an element 的定义:
然而在定义中并没有找到和异步操作无关的信息。
接着去查看 insertBefore 的具体定义,后果也是一样,没有证据阐明 insertBefore 波及到了异步操作。
那么同步的操作却导致了异步的后果,那么问题很可能不是出在渲染函数中,于是我间接应用 console.log() 打印虚构 DOM,果然,失去的是最新的虚构 DOM:
console.log(vnode);
setTimeout(() => {
vnode.children = [
{
type: "input",
props: {value: "请输出关键字",},
},
];
});
查阅了一些帖子后发现有人提到在《你不晓得的 JavaScript 中卷》中有问题的答案:
异步控制台
并没有什么标准或一组需要指定 console.* 办法族如何工作——它们并不是 JavaScript 正式的一部分,而是由宿主环境 (请参考本书的“类型和语法”局部) 增加到 JavaScript 中的。因而,不同的浏览器和 JavaScript 环境能够依照本人的志愿来实现,有时候这会引起混同。
尤其要提出的是,在某些条件下,某些浏览器的 console.log(..) 并不会把传入的内容立刻输入。呈现这种状况的次要起因是,在许多程序 (不只是 JavaScript) 中,I/O 是十分低速的阻塞局部。所以,(从页面 /UI 的角度来说)浏览器在后盾异步解决控制台 I/O 可能进步性能,这时用户甚至可能基本意识不到其产生。
举例
同时书中给出了解决方案:
如果遇到这种少见的状况,最好的抉择是在 JavaScript 调试器中应用断点,而不要依赖控制台输入。次优的计划是把对象序列化到一个字符串中,以强制执行一次“快照”,比方通过 JSON.stringify(..)。
问题解决:
let vnodeStr = JSON.parse(JSON.stringify(vnode));
console.log(vnodeStr);
参考资料
- Dom Standard
- console.log 是异步流?感觉本人貌似踩了个坑
- 《你不晓得的 JavaScript 中卷》