0

我正在编写一个简短的程序来了解 JavaScript 中的 Promises。

该程序的目标是将数字列表(从 5 减少到 0)打印到 HTML 页面上,每个数字之间有 0.5 秒的延迟。打印 0 后,会弹出一个确认框,允许用户再次打印相同的数字或停止。

目前,下面的代码大部分都在工作,但在内部循环(在countdown()函数中)的第一次和第二次迭代期间,它的行为非常奇怪——在打印第一次54.

我在 chrome dev 中对其进行了很多调试,试图弄清楚发生了什么,所以我在代码部分下面包含了一个关于程序实际在做什么(或似乎在做什么)的分步指南,用粗体表示的奇怪行为。

这是一个没有标记的大学作业,我设法难倒了我的教授,所以非常感谢任何帮助。提前致谢!!

// wait time for setTimeout
var wait = 500;

function timer(ms) {
  return new Promise((res) => {
    setTimeout(res, ms);
  });
}

async function countdown() {
  for (let i = 5; i >= 0; i--) {
    document.write("<br>");
    document.write(i);
    console.log(i);
    await timer(wait).then();
  }
  var c = confirm("Do you want to go again?");
  document.write("<br>User Confirm:");
  document.write(c);
  console.log(c);
  return c;
}



async function repeatRun() {
  var prom = new Promise(async(res, rej) => {
    r = await countdown();
    if (r) {
      res();
    } else {
      rej();
    }
  });
  prom.then(
    data => {
      document.write("<br>RERUN");
      console.log("RERUN");
      repeatRun();
    },
    error => {
      document.write("<br>ENDED");
      console.log("ENDED");
    }
  );
}

repeatRun();
<!DOCTYPE html>
<html>

<head>
  <title>Countdown</title>
</head>

<body>
  <h1>Countdown</h1>
  <p>Internet Applications Ex1.</p>
</body>

</html>

这是我的程序一步一步做的事情:

  1. 显示 HTML 页面标题等

  2. 进入script标签

  3. 进入repeatRun()

  4. 创建 Promise 变量prom并输入countdown()

  5. 循环的第一次迭代for(即i=5

    5.1。prints<br>5using document.write(),两者都附加到 HTML 正文中

    5.2. 进入timer()

    5.3. 返回new Promise

    5.4. 这个承诺返回到prom.then() 内部repeatRun()而不是await timer()像我预期的那样调用

    之后我尝试过这个有和没有.then(),它做同样的事情[这发生在 Chrome 调试器上的一步]

  6. 退出script标签

  7. 重新进入script标签,但不是从头开始:它返回for循环并减少i

    当前的 HTML 文件:

    <html>
    <head>
    <title>Countdown</title>
    </head>
    <body>
    <h1>Countdown</h1>
    <p>Internet Applications Ex1.</p>
    <script>...</scri pt>
    <br>
    "5"
    </body>
    </html>
    
  8. 下一个 document.write() 调用,而不是附加<br>到 HTML 正文,用 替换旧的 HTML 正文<br>head标记也被删除

  9. 下一个 document.write() 将(现在为 4)附加i到新的 HTML 文件当前的 HTML 文件中:

    <html>
    <head></head>
    <body>
    <br>
    "4"
    </body>
    

这是程序开始按预期运行的地方 10. 进入timer()函数,然后返回countdown()11. 按预期循环直到i=0

11.1. `document.write()` appends to HTML body instead of rewriting 

11.2. `timer()` function is called and returns to `countdown()` function afterwards
  1. 在这个循环之后,弹出确认窗口:我点击“确定”并true存储在c,打印使用document.write(),返回并存储在r
  2. 因为r=true,if成功并被res()调用
  3. 输入prom.then()然后data =>并正确document.write附加"<br>RERUN"到 HTML 正文
  4. repeatRun()函数被递归调用
  5. 创建新的 promise var 并调用countdown()
  6. 这一次,for循环按预期发生(即在步骤 11 中)从i=5i=0
  7. 循环结束后,我在确认窗口中点击“取消”,c设置为false,打印,返回并存储在r
  8. 因为r=false,if失败并被rej()调用
  9. 输入prom.then()然后error =>和 document.write 正确附加"<br>ENDED"到 HTML 正文
  10. 退出script标签
4

1 回答 1

0

documentation.write() 的 MDN 文档

注意:因为 document.write() 写入文档流,所以在关闭(加载)的文档上调用 document.write() 会自动调用 document.open(),这将清除文档。

所以第一次(第一次迭代)文档没有完全加载,这意味着它是打开的,所以document.write()就像往常一样工作。但是在第一次迭代之后,文档以某种方式完成了加载,因此文档现在已关闭,现在当它调用document.write()它时,它必须再次打开文档,因为它已关闭,这会清除整个文档(5被替换为4)和其余的迭代文档保持打开状态,因此它像往常一样工作。

您不应该使用document.write(),使用任何其他方法来更改页面的内容。

于 2020-10-22T18:27:55.590 回答