天天看點

body click js 委托_JS 事件循環

body click js 委托_JS 事件循環

程序 線程

  • CPU 配置設定資源的最小機關是程序,同一個時間内單個 CPU 隻能運作一個程序,單個 CPU 一次隻能運作一個任務
  • CPU 排程的最小機關是線程,一個程序裡面包含多個線程。
  • 可以看看阮老師的這篇文章,程序與線程的一個簡單解釋

浏覽器的程序

  • 浏覽器主程序
    • 負責界面展示,使用者互動,子程序管理,檔案存取等
  • 插件程序
  • GPU 程序
    • 3d繪制
  • 網絡程序
  • 渲染程序
    • 主要負責将 HTML, CSS, JavaScript 轉換為使用者可互動的網頁,排版引擎 Blink 和
    • JavaScript 引擎 V8 就運作在渲染程序,預設每個 tab 一個渲染程序
    • 浏覽器核心

浏覽器的渲染流程

  • 解析 HTML 檔案,生成 DOM tree;同時解析 CSS 檔案以及樣式元素中的樣式資料,生成 CSS Rules
  • 建構 render tree:根據 DOM tree 和 CSS Rules 來建構 render tree,它可以讓浏覽器按照正确的順序繪制内容
  • 布局(layout / reflow):計算各元素尺寸、位置。
  • 繪制(paint):繪制頁面像素資訊。
  • 浏覽器将各層資訊發送給 GPU,GPU 将各層資訊合成(composite),顯示在螢幕上。

浏覽器核心

  • GUI 渲染線程
  • JS 引擎線程
    • JavaScript 是單線程的
    • GUI 渲染線程 與 JS 引擎線程是互斥的
    • JS 阻塞頁面加載
  • 事件觸發線程
  • 定時觸發器線程
  • 異步 http 請求線程

宏任務,微任務

  • 事件輪詢解釋:事件輪詢-阮一峰
  • JS 單線程
    • 單線程中如果同步執行的代碼很慢,會讓其它程度等待很長時間,這是同步阻塞。
    • 多線程會占用多倍的資源也會浪費多倍的資源,也不合理。
    • event_loop 是把需要等待的程式放到異步隊列,主調用函數執行完之後監聽,再執行異步隊列,整個過程就是個不斷的循環
    • JS 引擎遇到一個異步事件後并不會一直等待其傳回結果,而是會将這個事件挂起,繼續執行執行棧中的其他任務。當一個異步事件傳回結果後,js會将這個事件加入與目前執行棧不同的另一個隊列,我們稱之為事件隊列。被放入事件隊列不會立刻執行其回調,而是等待目前執行棧中的所有任務都執行完畢, 主線程處于閑置狀态時,主線程會去查找事件隊列是否有任務。如果有,那麼主線程會從中取出排在第一位的事件,并把這個事件對應的回調放入執行棧中,然後執行其中的同步代碼…,如此反複,這樣就形成了一個無限的循環。這就是這個過程被稱為“事件環(Event Loop)”
  • 宏任務 宿主環境提供的異步方法 都是宏任務 script,ui 渲染,setTimeout,setInterval、setImmediate
  • 微任務 語言标準提供 promise,mutationObserver,process.nextTick,Object.observe(已廢棄)
  • 預設先執行 script 腳本中的代碼 -> 會清空微任務(将所有的微任務全部執行完) -> 渲染頁面 -> 取出一個宏任務執行 -> 執行完畢後會再次情空微任務...
body click js 委托_JS 事件循環

微任務和宏任務執行

  • 浏覽器黃色
<!DOCTYPE html>
<html >
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <!-- script是一個宏任務 -->
  <script>
    document.body.style.background = 'red';
    console.log(1);
    // 在 setTimeout 執行前 會觸發一次渲染
    Promise.resolve().then(()=>{
      console.log(2);
      document.body.style.background = 'yellow';
    });
    console.log(3);
  </script>
</body>
</html>
           
  • 按鈕事件執行順序
<!DOCTYPE html>
<html >
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="button">點我啊</button>
  <script>
    button.addEventListener('click', ()=>{
        console.log('listener1');
        Promise.resolve().then(()=>console.log('micro task1'));
    });
    button.addEventListener('click', ()=>{
        console.log('listener2');
        Promise.resolve().then(()=>console.log('micro task2'));
    });
    // 點選按鈕之後的順序
    // listener1
    // micro task1
    // listener2
    // micro task2

    // 一個個的函數來取 每次執行完 會先處理目前定義的微任務
    button.click(); // click1() click2()
    // listener1 listener2 micro task1 micro task2
  </script>
</body>
</html>
           
  • promise 和 setTimeout
<!DOCTYPE html>
<html >
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    Promise.resolve().then(() => {
      console.log('Promise1')
      setTimeout(() => {
        console.log('setTimeout2');
      }, 0);
    });

    setTimeout(() => {
      console.log('setTimeout1');
      Promise.resolve().then(() => {
        console.log('Promise2');
      });
    }, 0);
    // Promise1 setTimeout1 Promise2 setTimeout2
  </script>
</body>
</html>
           
  • 執行順序
<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
  <script>
    console.log(1);
    async function async () {
      console.log(2);
      await console.log(3); // Promise.resolve(console.log(3)).then(console.log(4))
      console.log(4);
    }
    setTimeout(() => {
      console.log(5);
    }, 0);
    const promise = new Promise((resolve, reject) => {
      console.log(6); // new Promise 代碼會立即執行
      resolve(7);
    })
    promise.then(res => { // 第一個微任務
      console.log(res)
    });
    async (); 
    console.log(8);
    // 1 6 2 3 8 7 4 5
  </script>
</body>
</html>
           
  • 執行順序
<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
  <script>
    console.log('script start');

    setTimeout(function() {
      console.log('setTimeout');
    }, 0);

    Promise.resolve().then(function() {
      console.log('promise1');
    }).then(function() {
      console.log('promise2');
    });

    console.log('script end');

    // script start
    // script end
    // promise1
    // promise2
    // setTimeout
  </script>
</body>
</html>
           
  • 一段變态的代碼
// 1 7 6 8
  console.log('1');
  setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
      console.log('3');
    });
    new Promise(function(resolve) {
      console.log('4');
      resolve();
    }).then(function() {
      console.log('5')
    });
  }, 0);
  process.nextTick(function() {
    console.log('6');
  });
  new Promise(function(resolve) {
    console.log('7');
    resolve();
  }).then(function() {
    console.log('8')
  });

  setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    });
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    });
  }, 0);