在函数中执行.innerHTML

时间:2019-04-11 15:20:27

标签: javascript asynchronous innerhtml

我想在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秒钟,然后更新我的div。

我希望我的代码:

等待1秒钟, 更新div, 等一秒钟 更新div, 等一秒钟 更新div

3 个答案:

答案 0 :(得分:1)

您可以尝试使用setTimeout

使用功能

我做了这个功能,可以很容易地提供要更新的对象数组。

.as-console-wrapper { max-height: 100% !important; top: 0; }

样品用量:

/* 
  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(); ,然后在1000毫秒(1秒)后调用one(),然后在1000毫秒(1秒)后调用two()

答案 1 :(得分:1)

Promise可以解决:

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>

您也可以使用setTimeoutsetInterval来做到这一点,但是我的经验是,使用Promise更加可靠/稳定。

要立即显示第一个文本,只需将第一个呼叫showTextAfterMS更改为showTextAfterMS('bla', '#el1', 0)

修改

使用Promise是正确的解决方案的原因最终植根于JavaScript的运行时概念。简而言之,这是因为从技术上讲setTimeoutsetInterval都是异步动作,因为它们都由JavaScript event loop 处理。在MDN上可以找到事件循环和JavaScript的一般并发模型的详尽解释。

简而言之:必须执行的每个动作都被推送到运行时必须运行的Queue个动作的末尾,好吧,运行。这样,可以处理来自UI的动作以及其他动作,例如超时和间隔。运行时会逐步处理这些操作,但是它们可能需要不同的时间才能完成。这是因为运行时会运行到完成状态,这意味着每个操作都在 之后被处理,而宝贵的操作已被完全处理。由于setTimeoutsetInterval产生的动作都放在了Queue上,因此毫秒数不能保证相应函数被调用的时间。这是保证的最短时间,它们在执行之前就流逝了。这使得它们两个都产生异步动作

但是,从建筑的角度来看,您需要的是一种可靠且可扩展的方式来实现序列异步操作。这就是Promise发挥作用的地方。

挥舞着一点,我们可以说,由于事件循环的工作方式,我们可以通过使用回调函数来获得相同的解决方案,而无需使用 Promise。它已经一次调用了一个功能,对吗?因此,这是一个基于回调的“平等”解决方案:

// 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>

它同样运作良好,并允许您以可靠的方式链接操作。缺点是:

  • 它的伸缩性不是很好。要链接更多操作,您需要更深层的嵌套,因为必须在成功回调函数内部将新操作称为
  • 您必须手工嵌套 。因此,嵌套的深度越深,跟踪代码流就越困难。这就是为什么人们称其为“厄运金字塔”。想象一下,必须在文本中混合20个元素。
  • 查看它的签名:showTextAfter :: Number -> String -> String -> Function -> Function -> undefined。那个微不足道的功能有很多东西!仅传递前三个参数不是很酷吗?

我们可以通过从调用返回一个showTextAfter的新函数来减轻最后一个问题,该函数消耗onCompleteonError回调:

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解决的问题!它们允许您以可伸缩的方式 序列异步操作,并且更容易跟踪控制流。可以通过(本地)返回值(原位)返回值来消除上述所有问题,您可以将这些返回值“链接”到其他将在“将来”完成的异步步骤(这意味着它们可以成功完成,也可以使用{ {1}})。真正聪明的是,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'));

答案 2 :(得分:0)

您可以利用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();

参考:https://javascript.info/async-await