【问题标题】:How do I allow a webpage to update while a javascript is running?如何在 javascript 运行时允许网页更新?
【发布时间】:2010-10-15 02:18:22
【问题描述】:

必须有一种简单的方法来做到这一点,但我是 JS 新手。

我有一个 javascript 程序,它 (1) 接受用户输入,(2) 根据该输入更新网页,然后 (3) 执行冗长的计算。问题是网页在冗长的计算之后才注册更新。有没有办法暂停执行,以便页面可以在长时间计算之前更新?

我尝试过 setTimeout 和 window.setTimeout,但它们没有任何区别。

该程序用于玩游戏:用户输入一个动作,脚本更新位置,然后计算其下一步动作。 postMessage 使用 div.innerHTML 打印文本消息; buttonFn 从用户那里获取输入,更新位置,打印一条消息,然后开始计算机计算。

function buttonFn(arg){
    var hst = histButt;
    hst.push(arg);
    var nwmv = hst.clone();

    postMessage("New move: " + nwmv.join());
    if(status == opposite(comp) && !pauseQ){
    var mvsposs = movesFromPos(posCur,status);
    if(mvsposs.has(nwmv)){
        updatePosCur(nwmv);
        //waitasec();
        if(comp == status && !pauseQ){
        compTurn();
        };
    }
    else{
        histButt = nwmv;
    };
    };
};

【问题讨论】:

  • 一个代码示例在这里会有所帮助...
  • 所有进程都在客户端处理?
  • 函数 postMessage(txt){ messageHist.push(txt); messageHist = messageHist.slice(1); var mesdiv = document.getElementById("messageDiv"); //messageHist.reverse(); mesdiv.innerHTML = messageHist.join("
    "); //messageHist.reverse(); };
  • 在处理stackoverflow.com/questions/51352/…时使用微调器
  • 将代码放在原始问题中,而不是 cmets

标签: javascript html


【解决方案1】:

是的,像这样调用你的函数。使用 setTimeout 将允许在您的 JS 执行之前进行页面重排。

function buttonFn(arg){
    var hst = histButt;
    hst.push(arg);
    var nwmv = hst.clone();

    postMessage("New move: " + nwmv.join());
    if(status == opposite(comp) && !pauseQ){
    var mvsposs = movesFromPos(posCur,status);
    if(mvsposs.has(nwmv)){
        updatePosCur(nwmv);
        //waitasec();

        if(comp == status && !pauseQ){
        setTimeout(function(){
          compTurn();
        },0);

        };
    }
    else{
        histButt = nwmv;
    };
    };
};

请记住,JS 对事件驱动非常友好。如果你能把东西搬走,然后再打电话给他们做。这是我们支持多线程行为的唯一方法。

setTimeout

【讨论】:

  • 0ms这个参数是什么意思?
  • 告诉JS引擎延迟执行。通过将长时间运行的函数放在函数闭包中,JS 将执行 buttonFn 的剩余部分,然后执行 setTimeout 内的任何内容。如果存在浏览器重排(DOM 已更改),这也会在 compTurn 运行之前发生
  • 谢谢!那行得通!但是为什么有必要将 compTurn() 包装在一个函数构造中呢?为什么是 0ms 而不是 100ms?
  • 你可以放任何你想要的东西,但我认为你不希望 compTurn 稍后运行。您只希望应用程序具有响应性。 setTimeout 在这么多毫秒后执行传递给它的函数,在本例中为 0 毫秒。如果您只是将 setTimeout 放在您的 compTurn() 之上,它将在 0 毫秒后不执行任何操作并继续以程序方式运行您的其余代码。
  • 非常感谢!我认为我的错误只是使用 setTimeout(compTurn(),100),我没有意识到表达式必须被包装。引用它似乎也有效。
【解决方案2】:

如果您只需要支持现代浏览器(或者如果您使用转译器),那么您现在可以使用 ES6 功能使这变得更容易,并且更符合原始提问者试图做的风格。 (我意识到这个问题已经有 8 年历史了 - 一个新的、更新的答案没有害处!)

例如,您可以这样做:

// helper function to use a setTimeout as a promise.
function allowUpdate() {
  return new Promise((f) => {
    setTimeout(f, 0);
  });
}

// An infinitely looping operation that doesn't crash the browser.
async function neverStopUpdating(someElement) {
  let i = 0;
  while (true) {
    someElement.innerText = i;
    i++;
    await allowUpdate();
  }
}

如果您尝试进行硬计算,您需要确保不要过于频繁地等待 - 在此示例中,在撰写本文时,在 Chrome 中,i 每秒仅增加约 150,因为setTimeout 的上下文切换并不快(如果您不为更新而让步,您将在一秒钟内获得数十万个)。您可能希望找到一个平衡点,或者总是在允许更新之前执行一些迭代,或者例如。在您的循环中调用 Date.now() 并在自上次允许更新后 100 毫秒后产生更新。

【讨论】:

    【解决方案3】:

    您可以进行更新,稍等片刻,然后进行计算。

    您可以在支持它们的浏览器上使用webworkers

    没有实际代码,这是我能给你的最佳答案。

    【讨论】:

    • 从未听说过网络工作者,我会检查一下,谢谢。我如何“等待一点时间”?我认为这就是 setTimeout 应该做的。
    • @Andrew,如果 setTimeout 不起作用,听起来你没有足够的时间进行重绘。
    • 我试过给它最多 5 秒,这还不够吗?
    【解决方案4】:

    JavaScript 是单线程的。如果你做你的计算服务器端,你可以通过异步调用的 ajax 获得结果,而不是阻塞你的 ui。

    【讨论】:

    • 因为计算时间可能很长,我认为让客户来做更合适。
    猜你喜欢
    • 2011-10-14
    • 2017-04-16
    • 2015-11-24
    • 2015-09-17
    • 1970-01-01
    • 2018-10-28
    • 2012-11-29
    • 2021-08-28
    • 1970-01-01
    相关资源
    最近更新 更多