xxleyi / learning_list

聚集自己的学习笔记
10 stars 3 forks source link

一网打尽 JS async await promise mutate setTimeout microtask macrotask 的执行顺序问题 #212

Open xxleyi opened 4 years ago

xxleyi commented 4 years ago

JS 异步代码执行顺序问题:

async function fn() {
  await new Promise(r => (console.log(1), r())).then(()  => console.log(2))
  setTimeout(() => console.log(9))
  console.log(3)
}
fn()
console.log('u')
Promise.resolve().then(() => console.log(4))
console.log('f')

async function fn() {
  await new Promise(resolve => {
    console.log(1)
    setTimeout(resolve)
  }).then(() => console.log(2))
  setTimeout(() => console.log(9))
  console.log(3)
}
fn()
console.log('u')
Promise.resolve().then(() => {
  console.log(4)
})
console.log('f')

async function bar() {
  async function fn() {
    await new Promise(resolve => {
      console.log(1)
      resolve()
    }).then(() => console.log(2))
    setTimeout(() => console.log(9))
    console.log(3)
  }
  fn()
  console.log('u')
  Promise.resolve().then(() => console.log(4))
  console.log('f')
}

bar().then(() => console.log('t'))

最后以一篇强悍的 blog 收尾:Tasks, microtasks, queues and schedules - JakeArchibald.com

除了未涉及 await 之外(那时候还没有),将其他几种异步讲解的异常清晰,还配有动画图示。

In summary:


包圆版,两种情况:

关键点:

<!-- 参考:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ -->
<!DOCTYPE html>
<html>

<head>
  <style>
    div {
      display: block;
    }

    .outer-test {
      background: #D4D4D4;
      padding: 25px;
      width: 92px;
      margin: 0 auto;
    }

    .inner-test {
      background: #ADADAD;
      padding: 46px;
      width: 0;
    }
  </style>
</head>

<body>
  <div class="outer-test">
    <div class="inner-test">
    </div>
  </div>
</body>
<script>
  // Let's get hold of those elements
  var outer = document.querySelector('.outer-test');
  var inner = document.querySelector('.inner-test');

  // Let's listen for attribute changes on the
  // outer element
  new MutationObserver(function () {
    console.log('mutate');
  }).observe(outer, {
    attributes: true
  });

  async function foo() {
    await new Promise(resolve => {
      console.log(1)
      resolve()
    }).then(() => console.log(2))
    setTimeout(() => console.log(3))
    console.log(4)
  }

  async function onClick() {
    console.log('click')
    foo()
    Promise.resolve().then(() => console.log(5))
    outer.setAttribute('data-random', Math.random())
  }

  // …which we'll attach to both elements
  inner.addEventListener('click', onClick);
  outer.addEventListener('click', onClick);
  // trigger click using script
  inner.click();
</script>

</html>
xxleyi commented 4 years ago

一道结合 click 触发时机和 Promise 的有趣题目,本质原因也是 ScriptJob 能够建栈

<!DOCTYPE html>
<html>

<body>
  <a id='link' href='http://www.google.com'>link</a>
</body>
<script>
  const link = document.getElementById('link')
  const nextTick = new Promise(resolve => link.addEventListener('click', resolve))
  nextTick.then(e => {
    e.preventDefault()
    console.log('e.preventDefault()')
  })
  link.addEventListener('click', () => console.log('click link'))
  // 用或不用此处的 click,行为表现是否一致?为什么不一致?
  link.click()
</script>

</html>