DataTables列渲染时二次AJAX请求向数组推值出现初始空值异常
核心出错原因
问题根源是JavaScript单线程事件循环的执行规则,结合异步AJAX的非阻塞特性导致,和DataTables本身的渲染逻辑没有本质冲突。
数组特殊表现的底层逻辑
整个执行流完全遵循浏览器的运行规则,可以拆解为固定步骤:
- DataTables执行单元格
render方法时,首先进入主线程同步执行栈: - 初始化空数组
tmp = [],瞬间完成内存分配 - 同步遍历
data数组,每遍历到一个条目就调用一次$.get发起AJAX请求 - 这里的
$.get默认开启异步模式,调用后不会等待服务器响应,会把对应的回调函数直接推到浏览器的异步任务队列中,立刻返回、不阻塞后续代码执行 forEach循环跑完所有条目后,同步执行栈立刻向下推进:- 执行
console.log(tmp),这一时刻所有AJAX请求都还在网络传输中,对应的回调函数根本没被触发执行,tmp数组完全没被修改,所以输出为空 - 执行
return $(currentCell).text(tmp),把空数组写入单元格,render函数的同步逻辑执行完毕,退出执行栈 - 等所有AJAX请求拿到服务器响应后,浏览器才会依次把异步队列里的回调拿出来执行,每执行一次回调就给
tmp数组push一个返回的名称值: - Chrome控制台对数组、对象这类引用类型的打印是动态追踪内存地址,不是存储打印时刻的快照,所以之前在控制台打印的空数组,会随着后续
tmp的修改同步展示后续被push进去的"Endkunden"、"Händler"等值,造成“数组自己慢慢变化”的错觉
渲染失效的直接逻辑
因为render函数在执行完同步逻辑后就已经返回了空内容,等后续AJAX回调执行往tmp里追加值的时候,render函数已经完全执行结束,没有任何代码主动把更新后的tmp值重新写入单元格,最终就出现了单元格渲染为空的结果。
注:如果刻意给
$.get加上async: false配置把请求改成同步阻塞模式,确实可以让tmp在同步执行栈跑完前收集完所有值,但这种做法会冻结浏览器主线程,网络请求慢的时候会导致页面完全无响应,属于不推荐的实现方式。
内容的提问来源于stack exchange,提问作者DBR
相关产品推荐
相关产品推荐

