microtask-demo2

HTML

<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<div id="content">
  <div class="code-source">var outer = document.querySelector('.outer'); var inner = document.querySelector('.inner'); new MutationObserver(function() {
    <span id="high1">console.log('mutate');</span> }).observe(outer, { attributes: true }); function onClick() {
    <span id="high2">console.log('click');</span>

    <span id="high3">setTimeout(function() {</span>
    <span id="high4">console.log('timeout');</span> }, 0);

    <span id="high5">Promise.resolve().then(function() {</span>
    <span id="high6">console.log('promise');</span> });

    <span id="high7">outer.setAttribute('data-random', Math.random());</span> } inner.addEventListener('click', onClick); outer.addEventListener('click', onClick);</div>
  <div class="tasks queue-wrapper">
    <div id="task-title" class="queue-title">tasks</div>
    <div id="task-content" class="queue-content"></div>
  </div>
  <div class="microtask queue-wrapper">
    <div id="microtask-title" class="queue-title">microtasks</div>
    <div id="microtask-content" class="queue-content"></div>
  </div>
  <div class="js-stack queue-wrapper">
    <div id="stack-title" class="queue-title">JS stack</div>
    <div id="stack-content" class="queue-content"></div>
  </div>
  <div class="log queue-wrapper">
    <div id="log-title" class="queue-title">log</div>
    <div id="log-content" class="queue-content"></div>
  </div>
  <div id="prev-btn">prev</div>
  <div id="next-btn">next</div>
  <div class="alert-window"></div>
</div>

CSS

* {
  margin: 0;
  padding: 0;
  font-family: 'Microsoft Yahei';
}

#content {
  position: relative;
  width: 700px;
  height: 500px;
  margin: 0 auto;
  border: 1px solid gray;
  background-color: #e0e0e0;
}

.code-source {
  position: relative;
  width: 680px;
  height: 290px;
  background-color: #3b3b3b;
  overflow: auto;
  color: #ececec;
  white-space: pre-wrap;
  font-size: 16px;
  padding: 0 10px;
}

.code-source p {}

.queue-wrapper {
  position: relative;
  width: 100%;
  height: 40px;
  border-top: 1px solid gray;
  border-bottom: 1px solid gray;
  font-size: 0;
}

.queue-title {
  display: inline-block;
  vertical-align: top;
  width: 90px;
  height: 100%;
  padding: 0 5px;
  background-color: #bdbdbd;
  line-height: 40px;
  color: #242424;
  font-size: 16px;
}

.queue-content {
  display: inline-block;
  width: 590px;
  height: 100%;
  line-height: 40px;
  padding: 0 5px;
  background-color: #ececec;
  vertical-align: top;
  font-size: 16px;
  font-size: 0;
}

.queue-item {
  display: inline-block;
  width: auto;
  height: 35px;
  padding: 0 4px;
  margin: 0 2px;
  background-color: #e0e05b;
  vertical-align: middle;
  font-size: 16px;
  line-height: 35px;
  color: #393939;
}

.queue-highlighted {
  background-color: #ff5100;
}

span.selected {
  background-color: #959595;
}

#next-btn {
  position: absolute;
  width: 50px;
  height: 35px;
  right: 10px;
  bottom: 3px;
  background-color: gray;
  text-align: center;
  line-height: 35px;
  border: 1px solid #8d8d8d;
  border-radius: 4px;
  box-shadow: 1px 1px 4px 0px;
  cursor: pointer;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

#prev-btn {
  position: absolute;
  width: 50px;
  height: 35px;
  left: 10px;
  bottom: 3px;
  background-color: gray;
  text-align: center;
  line-height: 35px;
  border: 1px solid #8d8d8d;
  border-radius: 4px;
  box-shadow: 1px 1px 4px 0px;
  cursor:...

JavaScript

(function() {
  var taskContent = document.getElementById("task-content");
  var microContent = document.getElementById("microtask-content");
  var stackContent = document.getElementById("stack-content");
  var logContent = document.getElementById("log-content");
  var nextBtn = document.getElementById("next-btn");
  var prevBtn = document.getElementById("prev-btn");
  var $alert = $(".alert-window");
  //语句高亮器
  var mark = function(selector) {
    $(".code-source span").removeClass('selected');
    $(selector).addClass('selected');
    location.hash = selector.substring(selector.lastIndexOf("#"), selector.length);
  }
  //事件循环器
  var eventLoop = (function() {
    var events = [];
    var domBackups = [];
    var eventBackups = [];

    return {
      push: function(event) {
        events.push(event);
      },
      next: function() {
        var event = events.shift();
        if (!event) {
          return;
        }
        var content = document.getElementById("content");
        $(content).find('*').stop(false, true);
        var temp = content.cloneNode(true);
        domBackups.push(temp);
        eventBackups.push(event);
        event();
      },
      rollback: function() {
        var temp = domBackups.pop();
        if (!temp) {
          return;
        }
        events = Array.from([eventBackups.pop()]).concat(events);
        var content = document.getElementById("content");
        document.body.insertBefore(temp, content);
        document.body.removeChild(content);
        taskContent = document.getElementById("task-content");
        microContent = document.getElementById("microtask-content");
        stackContent = document.getElementById("stack-content");
        logContent = document.getElementById("log-content");
        nextBtn = document.getElementById("next-btn");
        prevBtn = document.getElementById("prev-btn");
        $alert = $(".alert-window");
        nextBtn.addEventListener("click", function(event) {
         ...