你能异步创建数千个 DOM 元素吗?

Rya*_*yan 6 javascript google-chrome

我正在构建一个表情符号选择器,最艰巨的任务是为每个表情符号创建约 1500 个 DOM 元素,这会阻止/使页面无响应约 500-700 毫秒。

我已经调试了这个,似乎 DOM 元素的创建阻止了 JS 执行的其余部分:

function load_emojis(arr){
  var $emojis = [];
  # arr.length = 1500
  _.each(arr, function(){
    $emojis.push($('<span/>').append($('<img/>')));
  });

  $('.emojis').html($emojis);
}
Run Code Online (Sandbox Code Playgroud)

有没有办法异步/在另一个线程中执行这整个事情,这样它就不会阻止跟随它的 JS?

我试图将它放在 setTimeout 中,但它似乎仍然在同一个线程中执行,因此仍然阻止了 JS 执行。

Sha*_*ger 5

JavaScript 不是线程的;就像大多数 UI 库一样,它在具有事件循环的单个线程中完成所有工作;异步行为可能会在后台线程中工作(JS 程序员不可见;他们不显式管理甚至不查看线程),但结果总是传递给单个前台线程进行处理。

元素渲染直到你的 JS 代码完成才真正完成,并且控制权返回到事件循环;如果你渲染的东西太多,当浏览器需要绘制它时就会出现延迟,你无能为力。您能想到的最多是通过显式创建元素而不是传递一叠文本进行解析来减少解析开销,但即便如此,您的选择也是有限的。

根据浏览器、月相等,可能有帮助的事情包括:

  1. 创建并填充一个根本不属于 DOM 的单个父元素,然后在完成填充后将该单个父元素添加到 DOM(可以避免涉及维护 DOM 结构的工作)
  2. 创建一个你要重复添加的结构的模板,然后使用cloneNode(True)复制该模板,并在之后填写小差异;这避免了解析 X 节点树的工作,因为它实际上是同一个节点树,通过一些属性调整重复了多次。
  3. 如果图像比视口大,只插入/渲染最初可见的元素,当用户滚动时在背景中添加其他元素(也可能主动添加它们,但数量足够小,并且它们之间有足够的setTimeout/setInterval窗口任何给定的插入都不会花费很长时间,并且 UI 保持响应)。
  4. “多图像数组”的一个重要问题是停止使用 1500 多个图像,而是使用单个整体图像。然后你要么:

    一种。通过 CSS 以给定的固定偏移量和大小重复使用整体图像(图像被解压缩和渲染一次,并且该图像的视图被重复映射到不同的偏移量或......

    湾 使用map/area标签插入的图像只有一次,但要点击行为不同的图像的每个部分(减少DOM布局工作提高到一个单一的形象,所有其他的DOM元素必须存在于树,但并不需要被渲染)