+5

Call Stack và Execution Context trong JavaScript

Mayfest2023

Execution Context

Execution context là nơi mà JavaScript code được thực thi. Mỗi lần ta gọi một function thì sẽ có một function execution context tương ứng được tạo ra dành cho function đó và code của function đó sẽ được thực thi bên trong function execution context đó.

Code của global thì sẽ được thực thi trong global execution context - được khởi tạo khi chương trình JavaScript được chạy.

Execution context gồm có 2 phần:

  • Thread of execution: Đi qua từng dòng code và thực thi từng dòng.
  • Memory: Lưu dữ liệu (variables) và code (function) để sử dụng.

Call Stack

Call stack giúp theo dõi chúng ta đang ở execution context nào - nghĩa là function nào đang được thực thi. Và giúp ta xác định sau khi hoàn thành function đó thì sẽ trở về nơi nào để tiếp tục thực thi chương trình. Nó hoạt động theo cơ chế LIFO (last in first out).

Tạm thời lý thuyết là vậy, chúng ta sẽ hiểu vai trò của chúng sau khi xem qua ví dụ dưới đây.

Ta có một chương trình nhỏ sau:

Khi chúng ta run chương trình trên ở trên, một global execution context sẽ được tạo ra kèm global memory, call stack lúc này thì chúng ta đang ở global().

Lúc này, thread of execution sẽ thực thi vai trò của nó là đi qua từng dòng code và thực thi lần luợt, như sau:

  • Dòng 1: Khai báo một constant num ở global memory và gán giá trị cho nó là 3
  • Dòng 3: Khai báo function multiplyBy2 ở global memory
  • Dòng 8: Khai báo một constant output và giá trị của nó lúc này là chưa xác định, lý do? Vì ta gán cho nó multiplyBy2(num), lúc này chưa xác định được giá trị.

Toàn cảnh tạm thời của ta đang có:

Ta giải quyết bằng cách gọi function multiplyBy2 và truyền vào argument num. Giá trị của num là gì? Đi đến global memory để tìm, là 3. Sau đó tiến hành gọi function multiplyBy2(3).

Như đã tìm hiểu ở phần lý thuyết, mỗi khi ta gọi một function thì một function execution context tương ứng sẽ được tạo ra để thực thi code của function đó.

Lúc này, multiplyBy2(3) cũng sẽ được đẩy vào call stack.

Lúc này ta đang ở function execution context của multiplyBy2(3), và thread of execution lại tiếp tục thực hiện nhiệm vụ của mình:

  • Gán giá trị cho parameter inputNumber: 3
  • Khai báo một constant result ở local memory và gán giá trị cho nó là: 3 * 2: 6
  • return result;
      1. JavaScript sẽ đi đến local memory và tìm giá trị của result: 6.
      1. Lấy giá trị vừa tìm được và return (trả về) cho constant output ở global memory.

Vậy là đã hoàn thành việc thực thi, function execution context ở trên sẽ được cleared (xoá). Lúc này multiplyBy2(3) sẽ bị lấy ra khỏi stack và ta trở lại global().

Thread of execution lại tiếp tục làm nhiệm vụ của mình, đi đến và thực thi dòng code tiếp theo.

  • Dòng 9: Khai báo một constant newOutput và gán giá trị cho nó là multiplyBy2(10). Tương tự như khi thực thi Dòng 8 nên chúng ta sẽ đi nhanh hơn.
    • multiplyBy2(10) được đẩy vào call stack
    • Một function execution context tương ứng được tạo ra để thực thi.
    • Thực thi từng dòng, và trả giá trị đã tính toán được cho newOutputglobal memory

Do đã thực thi xong nên function execution context ở trên sẽ được xoá. Lúc này multiplyBy2(10) sẽ bị lấy ra khỏi stack và ta trở lại global().

Vì chương trình đã hoàn thành nên global execution context cũng sẽ được cleared luôn.

Vậy là chúng ta đã cùng nhau tìm hiểu về cách execution context và call stack hoạt động. Ở bài viết sau chúng ta sẽ tìm hiểu về closure.

Bài này nằm trong chuỗi bài viết về JavaScript của em/ mình khi đang học, nếu có hiểu sai hay còn thiếu xót mong các bạn, anh chị góp ý!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí