参考代码:
function sleep( sleepDuration ){
var now = new Date().getTime();
while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
}
function submit_answer(label) {
let image = get_node('img.to_label')
let size = Math.floor(Math.random() * 500)
image.src = `http://via.placeholder.com/${size}x${size}`
setTimeout(sleep.call(this, 1000), 0)
}
从点击处理程序调用 submit_answer
。
所需功能:呈现图像,并强制用户等待1秒钟,然后以任何方式与页面进行交互。
实际功能:用户等待1秒钟,然后加载图像。
我认为setTimeout
会将sleep
放在队列中 - 我希望图像在等待之前呈现。如何强制图像渲染,然后强制用户等待?
答案 0 :(得分:1)
setTimeout()
和 setInterval()
将功能引用或代码作为字符串(但是,不要这样做)作为他们的第一个论点。你的代码:
setTimeout(sleep.call(this, 1000), 0)
传递sleep
的实际函数调用,这就是为什么你首先得到睡眠(它立即被调用)和图像加载第二次。函数调用的返回值最终被用作函数引用,但是sleep
没有返回值,所以undefined
最终被传递给定时器,所以没有任何反应计时器到期。该行必须是:
setTimeout(function(){ sleep.call(this, 1000) }, 0)
以便函数引用正确地成为第一个参数,并且不会立即调用sleep
。
来自文档:
<强>语法:强>
var timeoutID = scope.setTimeout( function [,delay,param1,param2,...]);
var timeoutID = scope.setTimeout( function [,delay]);
var timeoutID = scope.setTimeout(代码 [,延迟]);
注意:代码 一种替代语法,允许您包含字符串而不是函数,该函数在计时器到期时编译和执行。建议不要使用此语法,原因与使用eval()存在安全风险的原因相同。
此外,永远不会设置0
的定时器延迟。 JavaScript运行时是同步的,只有在没有其他任何操作时才会运行计时器中指定的回调函数。结果,你永远无法真正知道延迟最终将会是什么。将延迟视为等待函数运行所需的最短时间。话虽如此,我在某处读到,由于JavaScript运行时和浏览器的WebAPI之间存在延迟,因此绝对最小值为16毫秒。
现在,您需要能够捕捉图像实际渲染的时刻,并且可以使用 .requestAnimationFrame()
来完成。
然后,你需要做的事情要简单得多。您将计时器设置为在图像加载完成后立即启动,并通过在图像的load
事件上设置回调来完成。
但是,您的代码不会阻止用户与页面进行交互,因此您需要在页面上添加“掩码”以阻止交互。
我已经让计时器3秒,并在下面的片段中给出了一个灰色的面具,以更好地显示效果。
var mask = document.getElementById("mask");
function startRender() {
// Rendering started, run callback when next render occurs
requestAnimationFrame(rendered);
}
function rendered() {
sleep(3000); // Render complete
}
// Nothing happens until the image fires off its load event...
document.querySelector("img").addEventListener("load", function(){
// Run callback when next render occurs
requestAnimationFrame(startRender);
});
function preventKeystrokes(evt){
preventDefault();
}
function sleep(duration){
mask.classList.remove("hidden"); // Show mask to prevent interactions
window.addEventListener("keydown", preventKeystrokes); // prevent keystrokes
// Count to three
setTimeout(function(){
mask.classList.add("hidden"); // Remove mask
window.removeEventListener("keydown", preventKeystrokes); // Enable keyboard
}, duration);
}
#mask { position:fixed; top:0; left:0; z-index:99; background-color:rgba(0,0,0,.6); width:100%; height:100%; }
.hidden { display:none; }
<button>Try to click me!</button>
<img src="http://imgsrc.hubblesite.org/hvi/uploads/image_file/image_attachment/30466/STSCI-H-p1801a-m-2000x1692.png" alt="big image">
<div id="mask" class="hidden"></div>