如何在不冻结浏览器的情况下在网络浏览器中列出数千个表情符号?

时间:2019-06-20 11:07:35

标签: javascript arrays performance dom queue

我看过几个问题,但似乎没有一个能解决我的问题。 该项目需要在div(模式)内打开一个表情符号列表。因此,当用户按下表情符号按钮时,将出现带有表情符号的模态。如果我们列出了数百个表情符号,则几乎可以立即完成。如果我们放置数千个表情符号,则加载模态需要几秒钟。

我为片段提供了一个演示表情符号数组。 尝试了经典方法,也尝试了createDocumentFragment(灵感来自here),两者的效果相同。

寻找一种可以一次渲染一个表情符号(例如在队列中)的解决方案。我知道我可以将DOM元素推送到队列中,并且在加载DOM元素时可以移至下一个元素。唯一的问题是我不知道何时显示content.appendChild(button)fragment.appendChild(button)。我读过您可以使用setTimeout函数,但是我不知道该设置什么时间,或者在这种情况下是否建议使用该时间。

谢谢!

function showEmojis() {
  let symbols = [
    "☺", "☻", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", 
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", 
    "?" , "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "☹", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "☠", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?",  "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", 
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", 
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "☕", "?", "?", "?", "?", "?", "?", "?", "?"]

    // Just to a have big array with emojis
    for (var i = 0; i < 6; i++) {
        symbols = symbols.concat(symbols)
    }

    let content = document.getElementById("content")

    // Simple for
    /*
    for(var i=0; i < symbols.length; i++) {
        let unicode = symbols[i]
        
        let button = document.createElement("button")
        button.classList.add("emoji-button")
        button.innerHTML = unicode
        
        button.onclick = function() {
            console.log("selected")
        }
        
        content.appendChild(button)
    }*/

    // Document fragment
    var fragment = document.createDocumentFragment()

    for (var i = 0; i < symbols.length; i++) {
        let unicode = symbols[i]

        let button = document.createElement("button")
        button.classList.add("emoji-button")
        button.innerHTML = unicode

        button.onclick = function() {
            console.log("selected")
        }

        fragment.appendChild(button)
    }

    content.appendChild(fragment)
}
.emoji-show-button {
    font-size: 15px;
}

.emoji-button {
    width: 28px;
    height: 28px;
    padding: 0px;
    margin: 5px;
    background: white;
    border-style: none;
    font-size: 20px;
}
<button class="emoji-show-button" onclick="showEmojis()">Show emojis</button>
<div id="content"></div>

3 个答案:

答案 0 :(得分:1)

这似乎是浏览器/操作系统窗口管理器在使用表情符号(Unicode)时遇到的问题

一种解决方法是使用照片,就像(https://emojipedia.org/emojipedia/

答案 1 :(得分:1)

问题是您正在运行并在Show emojis按钮的click事件上创建按钮,这在用户每次单击emogi按钮时都会执行相同的代码 一些优化方法可能是

  1. 在窗口中运行此方法。加载
  2. 以异步方法运行此代码,以便在后台加载
  3. 隐藏文档片段,仅在用户单击按钮时显示它

不设置每个按钮的onclick侦听器,而是执行类似操作

<button id='button'> emoji</button>
<button id='button'> emoji2</button>

然后在您的js中

document.addEventListener('click', (event) => {
if (event.target.id === 'button') {
    console.log(event.target.innerHtml)
}

答案 2 :(得分:1)

您可以创建一个助手,该助手需要一个片段,并将其子元素大块地附加到容器中。通过包装每个在setTimeout中添加块的调用,其他javascript东西就有机会在两者之间运行。例如。如果用户按下表情符号或用户界面的其他部分,它将仅等待写入1个块,然后它才会响应。

您可能要调查由单个写入引起的开销,并检查最佳块大小。首先为每个块创建片段,然后仅对DOM写入1也是有意义的。我会把这个留给您或其他答复者来找出:)

function appendInChunks(fragment, container, chunkSize = 5) {
  function writeChunk() {
    for (let c = 0; c < chunkSize && fragment.firstChild; c += 1) {
      container.appendChild(fragment.firstChild);
    }
  }
  
  for (let i = 0; i < fragment.children.length; i += chunkSize) {
    setTimeout(writeChunk);
  }
}

function showEmojis() {
  let symbols = [
    "☺", "☻", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", 
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", 
    "?" , "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "☹", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "☠", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?",  "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", 
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", 
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
    "?", "?", "?", "?", "☕", "?", "?", "?", "?", "?", "?", "?", "?"]

    // Just to a have big array with emojis
    for (var i = 0; i < 6; i++) {
        symbols = symbols.concat(symbols)
    }

    let content = document.getElementById("content")

    // Simple for
    /*
    for(var i=0; i < symbols.length; i++) {
        let unicode = symbols[i]
        
        let button = document.createElement("button")
        button.classList.add("emoji-button")
        button.innerHTML = unicode
        
        button.onclick = function() {
            console.log("selected")
        }
        
        content.appendChild(button)
    }*/

    // Document fragment
    var fragment = document.createDocumentFragment()

    for (var i = 0; i < symbols.length; i++) {
        let unicode = symbols[i]

        let button = document.createElement("button")
        button.classList.add("emoji-button")
        button.innerHTML = unicode

        button.onclick = function() {
            console.log("selected")
        }

        fragment.appendChild(button)
    }

    appendInChunks(fragment, content);
}
.emoji-show-button {
    font-size: 15px;
}

.emoji-button {
    width: 28px;
    height: 28px;
    padding: 0px;
    margin: 5px;
    background: white;
    border-style: none;
    font-size: 20px;
}
<button class="emoji-show-button" onclick="showEmojis()">Show emojis</button>
<button onclick="console.log('ping')">press to check browser response</button>
<div id="content"></div>