Cảm ơn bạn!
Debug JavaScript hiệu quả bạn đã biết chưa?
Chào các bạn lại là homiedev trong chuỗi bài viết về học JavaScript cơ bản đây 😁. Trong bài viết này, chúng ta cùng học cách debug JavaScript nhé! cụ thể thì mình sẽ hướng dẫn các bạn debug JavaScript trên Chrome 😀. Cùng bắt đầu thôi nào!
Debugging JavaScript in Browser
Debugging là quá trình tìm kiếm và sửa lỗi trong các chương trình, phần mềm hoặc hệ thống máy tính. Các trình duyệt hiện nay và hầu hết các môi trường khác đều có debugging tools (công cụ gỡ lỗi). Đây là một UI trong developer tools giúp chúng ta có thể gỡ lỗi dễ dàng hơn.
Trong bài viết này, mình sẽ sử dụng Chrome để debug, vì nó có đủ tính năng cần thiết cho chúng ta 😀.
Sources panel của Chrome DevTools
Đầu tiên, để mở chrome dev tool các bạn ấn phím F12
(Mac: Cmd + Opt + I). Sau đó chọn vào Sources panel.
Một số phím tắt chrome các bạn nên biết: Phím tắt Chrome cực hay mà Web Developer nên biết.
Kết quả nhìn tương tự như trong hình:
Chúng ta click vào toggle button như trong hình để xem danh sách các files.
Các bạn tải source về và chúng ta tiến hành debug nhé 📂: homiedev_debug.rar
Sau khi tải source, các bạn mở file index.html
sau đó ấn phím F12
(Mac: Cmd + Opt + I) và chọn sources panel. Kết quả nhìn sẽ tương tự như sau:
Như hình trên các bạn có thể thấy, source panel có 3 phần:
- File Navigator chứa danh sách cái file HTML, JavaScript, CSS và các file khác, bao gồm cả hình ảnh được đính kèm vào trang.
- Code Editor hiển thị source code.
- JavaScript Debugging dùng để gỡ lỗi (debugging).
Bây giờ, các bạn có thể click vào Hide navigator ở code editor panel để ẩn danh sách các file giúp source code có thêm không gian hiển thị.
Console
Khi các bạn ấn Esc
, Console panel sẽ xuất hiện bên dưới source panel. Chúng ta có thể viết code và thực thi bằng cách ấn Enter
. Sau khi thực thi, kết quả sẽ hiện bên dưới.
Giả sử mình nhập 'blog' + ' homiedev.com'
, kết quả sẽ là blog homiedev.com
. Trong khi đó nếu hàm không return gì thì kết quả sẽ là undefined
.
Breakpoints
Sử dụng breakpoints cho phép chúng ta pause (tạm dừng) JavaScript code để xem xét.
Ở homiedev.debug.js
, các bạn click vào vùng trống bên trái dòng số 4 (không phải phía bên trong code) ✔. Nếu hiện màu xanh tại dòng 4 thì có nghĩa là chúng ta đã đặt một breakpoint tại đây, bây giờ bạn tiếp tục thêm một breakpoint ở dòng 8 nhé.
Kết quả ta sẽ được như hình sau:
Breakpoint là một điểm nơi trình gỡ lỗi (debugger) sẽ tự động tạm dừng việc thực thi JavaScript.
Khi code tạm dừng, chúng ta có thể xem các biến (variables) hiện có để debug.
Bên phải của source panel, ở Breakpoints pane chúng ta có thể quản lý các breakpoints, breakpoints pane có một số điểm hữu ích sau:
- Chuyển đến breakpoint trong code bằng cách nhấp vào một breakpoint bất kì trong Breakpoints pane.
- Tạm dừng breakpoint bằng cách bỏ chọn nó.
- Xóa breakpoint bằng cách nhấp chuột phải và chọn Remove breakpoint.
Kết quả:
Ở ví dụ trên, greet()
được thực thi trong quá trình tải trang, sau khi chúng ta đã đặt các breakpoint, cách dễ nhất để chạy debugger (trình gỡ lỗi) là reload trang. Các bạn có thể click vào icon reload hoặc ấn F5
với Windows, Linux hoặc Cmd + R
với Mac.
Khi đã đặt breakpoint, việc thực thi code sẽ tạm dừng ở dòng thứ 4:
Để kiểm tra trạng thái code hiện tại, ở bên phải source panel các bạn mở các dropdown (Watch, Call Stack, Scope,...), dưới đây là một số thông tin về các pane này:
Watch: hiện các giá trị hiện tại của biểu thức.
Để thêm một biểu thức, chúng ta nhấp vào dấu cộng +
(add watch expression) và thêm một biểu thức. Trình gỡ lỗi sẽ hiện giá trị này và tự động tính toán lại trong quá trình thực thi.
Call Stack: hiện thông tin nested calls chain
Tại thời điểm hiện tại, trình gỡ lỗi đang ở bên trong lệnh gọi greet()
, được gọi bởi script
trong index.html
(do không có function nào ở đó, nên nó được gọi là "anonymous").
Nếu chúng ta chọn vào một mục của stack (ví dụ: "anonymous"), trình gỡ lỗi sẽ chuyển đến nơi chứa code tương ứng.
Scope: thông tin của biến hiện tại
- Local hiển thị thông tin của các biến cục bộ. Chúng ta cũng có thể thấy các giá trị của chúng được hiển thị ở code editor.
- Global chứa các biến, hàm.
Lệnh "debugger"
Chúng ta có thể gọi lệnh "debugger"
để pause code. Cách làm này tương đương với sử dụng breakpoint (line-of-code breakpoint) ở trên mình đã giới thiệu. Khác nhau ở chỗ "debugger"
được đặt trong code của chúng ta, không phải trong DevTools UI.
function greet(name) {
let text = `Hi, my name is ${name}!`;
debugger; // tạm dừng tại đây ✋
displayText(text);
}
function displayText(text) {
alert(text);
}
Lệnh này chỉ hoạt động khi DevTools đang mở, nếu không thì trình duyệt sẽ bỏ qua.
Trace JavaScript code
Sources panel có các lệnh cho phép chúng ta xem qua quá trình thực thi mã của mình, từng dòng một và nhờ đó ta có thể tìm ra nơi code đang thực thi khác với mong đợi.
Các bạn để ý ở góc trên bên phải source panel sẽ có các button. Hãy cùng khám phá các button này nhé.
Resume: tiếp tục thực thi code. Nếu không có thêm breakpoint nào, thì quá trình thực thi sẽ tiếp tục. Phím tắt F8 hoặc ctrl + /
Chúng ta click vào button Resume và kết quả như sau:
Quá trình thực thi đã tiếp tục, và tạm dừng khi gặp một điểm breakpoint khác bên trong greet()
. Các bạn có thể nhìn vào "Call Stack" ở bên phải. Lúc này chúng ta đang ở bên trong displayText()
.
Step: chạy lệnh tiếp theo. Nếu bạn click button này thì chúng ta có thể lần lượt xem qua tất cả các câu lệnh script. Phím tắt F9.
📹 Các bạn có thể xem đoạn video dưới đây để xem cách hoạt động của Step nhé.
Step over: chạy lệnh tiếp theo, nhưng không đi vào một hàm. Phím tắt F10.
Tương tự như lệnh "Step" trước đó, nhưng hoạt động của step over có chút khác biệt nếu câu lệnh tiếp theo là một lệnh gọi hàm (không phải là một lệnh built-in, như alert, mà là một hàm do chúng ta tạo ra).
Nếu chúng ta so sánh 2 lệnh step vs step over, lệnh "Step" sẽ chuyển sang một lệnh gọi hàm lồng nhau (nested function call) và tạm dừng việc thực thi ở dòng đầu tiên của nó, trong khi "step over" sẽ thực thi ẩn lệnh gọi hàm lồng nhau.
Việc thực thi sau đó sẽ bị tạm dừng ngay sau lệnh gọi hàm đó.
Sử dụng lệnh này nếu chúng ta không muốn xem điều gì xảy ra bên trong lệnh gọi hàm.
Step into: phím tắt F11
Tương tự như lệnh "step", nhưng có điểm khác trong trường hợp gọi hàm bất đồng bộ (asynchronous function calls).
Nếu bạn mới bắt đầu học JavaScript, thì có thể bỏ qua sự khác biệt, khi đã hiểu khái niệm asynchronous thì chúng ta có thể tìm hiểu kĩ hơn sự khác nhau giữa step vs step into là lệnh "Step" bỏ qua các hành động bất đồng bộ, chẳng hạn như setTimeout. "Step into" sẽ chờ để thực thi code nếu cần.
Step out: tiếp tục thực hiện cho đến khi kết thúc function hiện tại, phím tắt Shift + F11.
Mình lấy một ví dụ:
function updateHeader() {
const now = new Date();
const date = new Intl.DateTimeFormat("vi-VN").format(now);
const name = getName();
updateName(name, date); // C
}
function getName() {
const name = "homiedev.com"; // A
return name; // B
}
function updateName(name, date) {
console.log(name, date);
}
updateHeader();
Tìm hiểu về Intl trong JavaScript tại: Intl trong JavaScript là gì? Cách sử dụng Intl thông qua ví dụ
Ở ví dụ này có các breakpoint là A, B, C. Đầu tiên chúng ta sẽ ở breakpoint A. Khi bị tạm dừng bên trong một function không liên quan đến một lỗi bạn đang muốn xử lý, chúng ta có thể sử dụng lệnh "step out" để thực thi phần code còn lại của function.
Tiếp tục ví dụ trên, bằng cách ấn "step out", DevTools thực thi phần code còn lại trong getName()
là B trong ví dụ này, sau đó tạm dừng trên C.
Deactivate breakpoint: sử dụng button này nếu bạn muốn enable/disable toàn bộ breakpoints. Phím tắt ctrl + F8.
Pause on exceptions
Nếu chương trình của chúng ta gặp lỗi, chúng ta có thể mở trình gỡ lỗi, bật tùy chọn này và reload trang để xem vị trí gây ra lỗi tại thời điểm đó.
Như vậy là trong bài viết này, chúng ta đã cùng nhau tìm hiểu về debug JavaScript trên chrome. Đây là một công cụ gỡ lỗi giúp ích nhiều cho chúng ta 🥳.
Hi vọng bài viết giúp ích cho các bạn. Nếu có thắc mắc chúng ta cùng thảo luận bên dưới phần bình luận nhé!