JavaScript追加元素时的fetch异步行为:appendChild为何能正常生效?
原理说明
你猜测的异步逻辑是完全正确的,二者表现差异本质是代码执行时序不同 + DOM对象是引用类型、DOM树实时响应修改两个特性共同导致的,具体逻辑如下:
代码实际执行顺序
- 先创建空的
<tr>DOM对象,赋值给row变量,注意这里row存的是DOM对象的引用,不是值拷贝 - 调用异步请求函数
api_search,它内部的fetch请求不会阻塞主线程,.then()里的回调函数会暂时被挂起,等请求响应回来、且所有同步代码执行完毕后才会运行 - 同步执行
console.log(row):此时.then()回调还没触发,row的内容还是空的,所以打印结果是空tr元素 - 同步执行
inspireTable.appendChild(row):把当前空的tr插入到页面的表格DOM树中 - 等到
api_search请求成功返回,.then()回调执行:直接修改了row的innerHTML属性,因为row是已经插入到DOM树中的对象引用,DOM树会实时响应这个修改,自动更新页面上对应的tr内容,所以你最终能在页面看到填充后的完整数据
两个操作的核心差异
row本身自始至终都是同一个DOM对象的引用,不存在差异,差异是操作的时机和特性:
console.log(row)执行在异步回调触发前,记录的是row在该时间点的快照状态,所以是空的appendChild只是把空的row先行挂载到DOM树上,后续修改row的内容时,DOM会自动同步更新,你感知到的"appendChild能正确填充"其实是先插空节点、后静默更新的结果
验证方案
你可以在.then()回调的最后一行也加一行console.log(row),就能看到打印出来的是已经填充了内容的tr元素;也可以把appendChild操作移到.then()回调内部,执行逻辑就变成「先填充内容、再插入DOM」,最终效果完全一致。
内容的提问来源于stack exchange,提问作者AAM
相关产品推荐
相关产品推荐

