在函数中执行 .innerHTML
execute .innerHTML in a function
我想在js代码结束前更改我的HTML
我尝试使用异步函数,但我不确定这是否是正确的方法。
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
function one() {
wait(1000);
document.getElementById("1a").innerHTML = "bla";
}
function two() {
wait(1000);
document.getElementById("2b").innerHTML = "blabla";
}
function three() {
wait(1000);
document.getElementById("3c").innerHTML = "blablabla";
}
function start() {
one();
two();
three();
} start();
代码等待 3 秒,然后更新我的 divs。
我希望我的代码:
等1秒,
更新 div,
等待 1 秒,
更新 div,
等待 1 秒,
更新 div
您可以尝试使用 setTimeout。
使用函数
我制作了这个函数,它可以轻松提供您要更新的对象数组。
/*
timed_elemet_updates(array, int)
`elements` should be an array of objects which contains the
ID and HTML you want to update.
*/
function timed_element_updates(elements, seconds) {
var element = elements.shift();
document.getElementById(element.id).innerHTML = element.html;
setTimeout(timed_element_updates, (seconds * 1000), elements, seconds);
}
示例用法:
function start() {
var elements = [
{id: '1a', html: 'bla'},
{id: '2b', html: 'blabla'},
{id: '3c', html: 'blablabla'},
];
timed_element_updates(elements, 1);
}
start();
这个答案更简洁(重复的代码行更少),更易于使用(只需向数组添加更多元素),并且更可重用(每个元素没有新功能)
原答案
function one() {
document.getElementById("1a").innerHTML = "bla";
setTimeout(two, 1000);
}
function two() {
document.getElementById("2b").innerHTML = "blabla";
setTimeout(three, 1000);
}
function three() {
document.getElementById("3c").innerHTML = "blablabla";
}
one();
这将调用函数 one()
,然后它会在 1000 毫秒(1 秒)后调用 two()
,然后它会在 1000 毫秒(1 秒)后调用 three()
。
你可以利用 async functions
:
function one() {
console.log('document.getElementById("1a").innerHTML = "bla";')
}
function two() {
console.log('document.getElementById("2b").innerHTML = "blabla";')
}
function three() {
console.log('document.getElementById("3c").innerHTML = "blablabla";')
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function demo() {
await sleep(1000);
one();
await sleep(1000);
two();
await sleep(1000);
three();
}
demo();
这可以用 Promise
s 解决:
function showTextAfterMS (text, elemSelector, ms) {
return new Promise((res, rej) => {
let elem = document.querySelector(elemSelector);
if (!elem) {
return rej(new Error(`Cannot find element by selector: ${elemSelector}`));
}
setTimeout(() => {
elem.innerHTML = text;
res(elem);
}, ms);
});
}
showTextAfterMS('bla', '#el1', 1000).
then(() => showTextAfterMS('blabla', '#el2', 1000)).
then(() => showTextAfterMS('blablabla', '#el3', 1000));
<div id="el1"></div>
<div id="el2"></div>
<div id="el3"></div>
您也可以使用 setTimeout
或 setInterval
,但我的经验是使用 Promise
会更 reliable/stable。
要立即显示第一个文本,只需将对 showTextAfterMS
的第一次调用更改为 showTextAfterMS('bla', '#el1', 0)
。
编辑
之所以使用 Promise
s 是正确的解决方案,最终植根于 JavaScript 的 运行 时间概念。简而言之,这是因为技术上 setTimeout
和 setInterval
都是 异步操作 ,因为它们都由 JavaScript 事件循环。可以在 MDN.
上找到 JavaScript 的事件循环和一般并发模型的详尽解释
简而言之:必须执行的每个操作都被推到 运行 时间必须执行的 Queue
个操作的末尾,...好吧,运行。这样,来自 UI 的操作以及超时和间隔等其他操作都会得到处理。 运行时间会逐步处理这些操作,但是,它们可能需要不同的时间才能完成。那是因为 运行 时间 运行 秒完成,这意味着每个动作都在 之后 处理完珍贵的动作。因为 setTimeout
和 setInterval
产生的动作放在 Queue
上,毫秒数 不是调用相应函数的保证时间 .这是一个保证的最短时间,在它们被执行之前经过。这使得它们都产生 异步操作 .
但是,从体系结构 的角度来看,您需要的是一种可靠且可扩展的方式来排序异步操作。这就是 Promise
发挥作用的地方。
稍微挥手,我们可以说我们可以通过使用回调函数而不是Promise
来达到相同的解决方案,因为事件循环的工作方式.它已经一次调用一个函数,对吧?所以这是一个基于回调的 "equal" 解决方案:
// A "Promise equivalent", setTimeout based function with callbacks
function showTextAfter (ms, text, elemSelector, onComplete, onError) {
if (typeof ms !== 'number' || isNaN(ms)) {
return onError(new Error(`MS needs to be number, got: ${ms}`));
}
if (typeof text !== 'string') {
return onError(new Error(`Expected TEXT to be String, got: ${text}`));
}
let elem = document.querySelector(elemSelector);
if (!elem) {
return onError(new Error(`Cannot find element: ${elemSelector}`));
}
setTimeout(() => {
elem.innerHTML = text;
onComplete(elem);
}, ms);
}
showTextAfter(1000, 'bla', '#el1', (elem1) => {
showTextAfter(1000, 'blabla', '#el2', (elem2) => {
showTextAfter(1000, 'blablabla', '#el3', (elem3) => {
// do whatever you want with the elements. this example
// discards them
});
});
});
<div id="el1"></div>
<div id="el2"></div>
<div id="el3"></div>
它工作得同样好,并允许您以可靠的方式链接您的操作。它的缺点是:
- 它的扩展性不是很好。要链接更多操作,您需要更深的嵌套,因为必须在成功回调函数中调用新操作。
- 您必须手动嵌套。因此,嵌套得越深,跟踪代码流就越难。这就是为什么人们称它为 "pyramid of doom"。想象一下必须混合 20 个元素的文本。
- 看看它的签名:
showTextAfter :: Number -> String -> String -> Function -> Function -> undefined
。对于那个微不足道的小功能来说,这是很多东西!只传递前 3 个参数不是很酷吗?
我们可以通过 return 从对 showTextAfter
的调用中调用一个新函数来稍微缓解最后一个问题,它会消耗 onComplete
和 onError
回调:
function showTextAfter (ms, text, elemSelector) {
return function (onComplete, onError) { // <-- this little fellow here is what it's all about
if (typeof ms !== 'number' || isNaN(ms)) {
return onError(new Error(`MS needs to be number, got: ${ms}`));
}
if (typeof text !== 'string') {
return onError(new Error(`Expected TEXT to be String, got: ${text}`));
}
let elem = document.querySelector(elemSelector);
if (!elem) {
return onError(new Error(`Cannot find element: ${elemSelector}`));
}
setTimeout(() => {
elem.innerHTML = text;
onComplete(elem);
}, ms);
}
}
const showEl1 = showTextAfter(1000, 'bla', '#el1');
const showEl2 = showTextAfter(1000, 'blabla', '#el2');
const showEl3 = showTextAfter(1000, 'blablabla', '#el3');
showEl1(elem1 => {
showEl2(elem2 => {
showEl3(elem3 => {
// whatever
});
});
});
<div id="el1"></div>
<div id="el2"></div>
<div id="el3"></div>
是的,这样更好。但是,这并没有真正解决问题,对吧?
不过不要惊慌,因为这些正是 Promise
解决的问题!它们允许您以 可扩展的方式 对异步操作 进行排序,并且更容易跟踪 控制流 。上面的所有问题都可以通过具有(本机)"in place" return 值来消除,您可以 "chain" 其他异步步骤将完成 "in the future" (这意味着它们可以成功完成或者他们可以用 Error
来完成)。真正聪明的是,Promise
允许您链接下一个异步操作 而无需嵌套 。
查看我最初的(稍微修改过的)答案:
function showTextAfterMS (ms, text, elemSelector) {
return new Promise((onComplete, onError) => {
// type checking stuff...
let elem = document.querySelector(elemSelector);
setTimeout(() => {
elem.innerHTML = text;
onComplete(elem);
}, ms);
});
}
showTextAfterMS(1000, 'bla', '#el1'). // <-- no more nesting!
then(() => showTextAfterMS(1000, 'blabla', '#el2')).
then(() => showTextAfterMS(1000, 'blablabla', '#el3'));
<div id="el1"></div>
<div id="el2"></div>
<div id="el3"></div>
我想在js代码结束前更改我的HTML
我尝试使用异步函数,但我不确定这是否是正确的方法。
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
function one() {
wait(1000);
document.getElementById("1a").innerHTML = "bla";
}
function two() {
wait(1000);
document.getElementById("2b").innerHTML = "blabla";
}
function three() {
wait(1000);
document.getElementById("3c").innerHTML = "blablabla";
}
function start() {
one();
two();
three();
} start();
代码等待 3 秒,然后更新我的 divs。
我希望我的代码:
等1秒, 更新 div, 等待 1 秒, 更新 div, 等待 1 秒, 更新 div
您可以尝试使用 setTimeout。
使用函数
我制作了这个函数,它可以轻松提供您要更新的对象数组。
/*
timed_elemet_updates(array, int)
`elements` should be an array of objects which contains the
ID and HTML you want to update.
*/
function timed_element_updates(elements, seconds) {
var element = elements.shift();
document.getElementById(element.id).innerHTML = element.html;
setTimeout(timed_element_updates, (seconds * 1000), elements, seconds);
}
示例用法:
function start() {
var elements = [
{id: '1a', html: 'bla'},
{id: '2b', html: 'blabla'},
{id: '3c', html: 'blablabla'},
];
timed_element_updates(elements, 1);
}
start();
这个答案更简洁(重复的代码行更少),更易于使用(只需向数组添加更多元素),并且更可重用(每个元素没有新功能)
原答案
function one() {
document.getElementById("1a").innerHTML = "bla";
setTimeout(two, 1000);
}
function two() {
document.getElementById("2b").innerHTML = "blabla";
setTimeout(three, 1000);
}
function three() {
document.getElementById("3c").innerHTML = "blablabla";
}
one();
这将调用函数 one()
,然后它会在 1000 毫秒(1 秒)后调用 two()
,然后它会在 1000 毫秒(1 秒)后调用 three()
。
你可以利用 async functions
:
function one() {
console.log('document.getElementById("1a").innerHTML = "bla";')
}
function two() {
console.log('document.getElementById("2b").innerHTML = "blabla";')
}
function three() {
console.log('document.getElementById("3c").innerHTML = "blablabla";')
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function demo() {
await sleep(1000);
one();
await sleep(1000);
two();
await sleep(1000);
three();
}
demo();
这可以用 Promise
s 解决:
function showTextAfterMS (text, elemSelector, ms) {
return new Promise((res, rej) => {
let elem = document.querySelector(elemSelector);
if (!elem) {
return rej(new Error(`Cannot find element by selector: ${elemSelector}`));
}
setTimeout(() => {
elem.innerHTML = text;
res(elem);
}, ms);
});
}
showTextAfterMS('bla', '#el1', 1000).
then(() => showTextAfterMS('blabla', '#el2', 1000)).
then(() => showTextAfterMS('blablabla', '#el3', 1000));
<div id="el1"></div>
<div id="el2"></div>
<div id="el3"></div>
您也可以使用 setTimeout
或 setInterval
,但我的经验是使用 Promise
会更 reliable/stable。
要立即显示第一个文本,只需将对 showTextAfterMS
的第一次调用更改为 showTextAfterMS('bla', '#el1', 0)
。
编辑
之所以使用 Promise
s 是正确的解决方案,最终植根于 JavaScript 的 运行 时间概念。简而言之,这是因为技术上 setTimeout
和 setInterval
都是 异步操作 ,因为它们都由 JavaScript 事件循环。可以在 MDN.
简而言之:必须执行的每个操作都被推到 运行 时间必须执行的 Queue
个操作的末尾,...好吧,运行。这样,来自 UI 的操作以及超时和间隔等其他操作都会得到处理。 运行时间会逐步处理这些操作,但是,它们可能需要不同的时间才能完成。那是因为 运行 时间 运行 秒完成,这意味着每个动作都在 之后 处理完珍贵的动作。因为 setTimeout
和 setInterval
产生的动作放在 Queue
上,毫秒数 不是调用相应函数的保证时间 .这是一个保证的最短时间,在它们被执行之前经过。这使得它们都产生 异步操作 .
但是,从体系结构 的角度来看,您需要的是一种可靠且可扩展的方式来排序异步操作。这就是 Promise
发挥作用的地方。
稍微挥手,我们可以说我们可以通过使用回调函数而不是Promise
来达到相同的解决方案,因为事件循环的工作方式.它已经一次调用一个函数,对吧?所以这是一个基于回调的 "equal" 解决方案:
// A "Promise equivalent", setTimeout based function with callbacks
function showTextAfter (ms, text, elemSelector, onComplete, onError) {
if (typeof ms !== 'number' || isNaN(ms)) {
return onError(new Error(`MS needs to be number, got: ${ms}`));
}
if (typeof text !== 'string') {
return onError(new Error(`Expected TEXT to be String, got: ${text}`));
}
let elem = document.querySelector(elemSelector);
if (!elem) {
return onError(new Error(`Cannot find element: ${elemSelector}`));
}
setTimeout(() => {
elem.innerHTML = text;
onComplete(elem);
}, ms);
}
showTextAfter(1000, 'bla', '#el1', (elem1) => {
showTextAfter(1000, 'blabla', '#el2', (elem2) => {
showTextAfter(1000, 'blablabla', '#el3', (elem3) => {
// do whatever you want with the elements. this example
// discards them
});
});
});
<div id="el1"></div>
<div id="el2"></div>
<div id="el3"></div>
它工作得同样好,并允许您以可靠的方式链接您的操作。它的缺点是:
- 它的扩展性不是很好。要链接更多操作,您需要更深的嵌套,因为必须在成功回调函数中调用新操作。
- 您必须手动嵌套。因此,嵌套得越深,跟踪代码流就越难。这就是为什么人们称它为 "pyramid of doom"。想象一下必须混合 20 个元素的文本。
- 看看它的签名:
showTextAfter :: Number -> String -> String -> Function -> Function -> undefined
。对于那个微不足道的小功能来说,这是很多东西!只传递前 3 个参数不是很酷吗?
我们可以通过 return 从对 showTextAfter
的调用中调用一个新函数来稍微缓解最后一个问题,它会消耗 onComplete
和 onError
回调:
function showTextAfter (ms, text, elemSelector) {
return function (onComplete, onError) { // <-- this little fellow here is what it's all about
if (typeof ms !== 'number' || isNaN(ms)) {
return onError(new Error(`MS needs to be number, got: ${ms}`));
}
if (typeof text !== 'string') {
return onError(new Error(`Expected TEXT to be String, got: ${text}`));
}
let elem = document.querySelector(elemSelector);
if (!elem) {
return onError(new Error(`Cannot find element: ${elemSelector}`));
}
setTimeout(() => {
elem.innerHTML = text;
onComplete(elem);
}, ms);
}
}
const showEl1 = showTextAfter(1000, 'bla', '#el1');
const showEl2 = showTextAfter(1000, 'blabla', '#el2');
const showEl3 = showTextAfter(1000, 'blablabla', '#el3');
showEl1(elem1 => {
showEl2(elem2 => {
showEl3(elem3 => {
// whatever
});
});
});
<div id="el1"></div>
<div id="el2"></div>
<div id="el3"></div>
是的,这样更好。但是,这并没有真正解决问题,对吧?
不过不要惊慌,因为这些正是 Promise
解决的问题!它们允许您以 可扩展的方式 对异步操作 进行排序,并且更容易跟踪 控制流 。上面的所有问题都可以通过具有(本机)"in place" return 值来消除,您可以 "chain" 其他异步步骤将完成 "in the future" (这意味着它们可以成功完成或者他们可以用 Error
来完成)。真正聪明的是,Promise
允许您链接下一个异步操作 而无需嵌套 。
查看我最初的(稍微修改过的)答案:
function showTextAfterMS (ms, text, elemSelector) {
return new Promise((onComplete, onError) => {
// type checking stuff...
let elem = document.querySelector(elemSelector);
setTimeout(() => {
elem.innerHTML = text;
onComplete(elem);
}, ms);
});
}
showTextAfterMS(1000, 'bla', '#el1'). // <-- no more nesting!
then(() => showTextAfterMS(1000, 'blabla', '#el2')).
then(() => showTextAfterMS(1000, 'blablabla', '#el3'));
<div id="el1"></div>
<div id="el2"></div>
<div id="el3"></div>