如何在函数执行期间show/hide动画GIF?
How to show/hide animated GIF during the execution of a function?
我想在函数执行期间显示动画 GIF(微调器图标),然后在函数完成时隐藏 GIF。
但是,我正在实现的代码显然没有显示 GIF,因为该函数正在占用线程并且不允许显示 GIF。
示例:(https://jsfiddle.net/jzxu8cLt/)
HTML
<button onclick="go();">Go</button>
<span id="result"></span>
<hr>
<img style="display: none;" id="spinner" src="https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif">
JS
function longLoop() {
let count = 1000000000;
let result = 0;
for (let i = 1; i <= count; i++) {
result = i;
}
return result;
}
function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
let result = longLoop();
resultElement.innerHTML = result;
spinnerElement.style.display = 'none';
}
上面的 go() 函数应该在调用 long 运行 函数之前完成显示 GIF 的工作,然后在 long 运行 函数完成时隐藏 GIF。
但是,GIF 从来没有机会在浏览器中显示,我不知道如何让 GIF 显示。注意:如果我在调用 longLoop() 函数的行放置断点,GIF 将正确显示。
我需要做什么才能让 GIF 在 longLoop() 函数期间显示和动画化?
运行 你的 long 运行 并在 setTimeout 中恢复代码,省略计时参数或 0
将“立即”执行,或更准确地说,下一个事件循环,这将防止阻塞。
function longLoop() {
let count = 1000000000;
let result = 0;
for (let i = 1; i <= count; i++) {
result = i;
}
return result;
}
function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
setTimeout(() => {
let result = longLoop();
resultElement.innerHTML = result;
spinnerElement.style.display = 'none';
})
}
<button onclick="go();">Go</button>
<span id="result"></span>
<hr>
<img style="display: none;" id="spinner" src="https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif">
我建议您使用 async/await 在这里 pourpuse 的代码将更具可读性解决方案:
function longLoop(timeout) {
return new Promise(resolve => setTimeout(resolve, timeout));
}
async function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
let result = await longLoop(4000);
spinnerElement.style.display = 'none';
}
是的,你是对的,因为 JavaScript 是 single-threaded,longLoop 函数阻塞了事件循环,不给浏览器渲染 gif 的机会。
JsFiddle 解决方案:https://jsfiddle.net/12yf4tgd/
我使用 setTimeout 使 longLoop 函数异步并将其包装在 Promise 中,以便其他作业 运行 在 完成后完成。
function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
new Promise(resolve => setTimeout(() => {
resolve(longLoop())
}))
.then((result) => {
spinnerElement.style.display = 'none';
resultElement.innerHTML = result;
})
}
由于它由某些 Web Api 在别处处理,而不是在主调用堆栈上,因此不会阻塞。
如果你不想使用 .then() 因为所有嵌套,另一个选择是使 go() 和异步函数利用 async/await 语法。
async function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
let result = await new Promise((resolve, reject) => {
setTimeout(() => resolve(longLoop()))
})
spinnerElement.style.display = 'none';
resultElement.innerHTML = result;
}
它们的工作方式相同。
我想在函数执行期间显示动画 GIF(微调器图标),然后在函数完成时隐藏 GIF。
但是,我正在实现的代码显然没有显示 GIF,因为该函数正在占用线程并且不允许显示 GIF。
示例:(https://jsfiddle.net/jzxu8cLt/)
HTML
<button onclick="go();">Go</button>
<span id="result"></span>
<hr>
<img style="display: none;" id="spinner" src="https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif">
JS
function longLoop() {
let count = 1000000000;
let result = 0;
for (let i = 1; i <= count; i++) {
result = i;
}
return result;
}
function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
let result = longLoop();
resultElement.innerHTML = result;
spinnerElement.style.display = 'none';
}
上面的 go() 函数应该在调用 long 运行 函数之前完成显示 GIF 的工作,然后在 long 运行 函数完成时隐藏 GIF。
但是,GIF 从来没有机会在浏览器中显示,我不知道如何让 GIF 显示。注意:如果我在调用 longLoop() 函数的行放置断点,GIF 将正确显示。
我需要做什么才能让 GIF 在 longLoop() 函数期间显示和动画化?
运行 你的 long 运行 并在 setTimeout 中恢复代码,省略计时参数或 0
将“立即”执行,或更准确地说,下一个事件循环,这将防止阻塞。
function longLoop() {
let count = 1000000000;
let result = 0;
for (let i = 1; i <= count; i++) {
result = i;
}
return result;
}
function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
setTimeout(() => {
let result = longLoop();
resultElement.innerHTML = result;
spinnerElement.style.display = 'none';
})
}
<button onclick="go();">Go</button>
<span id="result"></span>
<hr>
<img style="display: none;" id="spinner" src="https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif">
我建议您使用 async/await 在这里 pourpuse 的代码将更具可读性解决方案:
function longLoop(timeout) {
return new Promise(resolve => setTimeout(resolve, timeout));
}
async function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
let result = await longLoop(4000);
spinnerElement.style.display = 'none';
}
是的,你是对的,因为 JavaScript 是 single-threaded,longLoop 函数阻塞了事件循环,不给浏览器渲染 gif 的机会。
JsFiddle 解决方案:https://jsfiddle.net/12yf4tgd/
我使用 setTimeout 使 longLoop 函数异步并将其包装在 Promise 中,以便其他作业 运行 在 完成后完成。
function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
new Promise(resolve => setTimeout(() => {
resolve(longLoop())
}))
.then((result) => {
spinnerElement.style.display = 'none';
resultElement.innerHTML = result;
})
}
由于它由某些 Web Api 在别处处理,而不是在主调用堆栈上,因此不会阻塞。
如果你不想使用 .then() 因为所有嵌套,另一个选择是使 go() 和异步函数利用 async/await 语法。
async function go() {
let spinnerElement = document.getElementById('spinner');
let resultElement = document.getElementById('result');
spinnerElement.style.display = 'block';
let result = await new Promise((resolve, reject) => {
setTimeout(() => resolve(longLoop()))
})
spinnerElement.style.display = 'none';
resultElement.innerHTML = result;
}
它们的工作方式相同。