Giới thiệu
Một tính năng mạnh mẽ khiến JavaScript trở nên độc đáo là khả năng hoạt động không đồng bộ thông qua các hàm gọi lại. Việc chỉ định các lệnh gọi lại không đồng bộ cho phép bạn viết mã dựa trên sự kiện, nhưng cũng khiến việc theo dõi lỗi xảy ra với trải nghiệm kéo tóc vì JavaScript không thực thi theo kiểu tuyến tính.
Thật may là giờ đây trong Công cụ của Chrome cho nhà phát triển, bạn có thể xem ngăn xếp lệnh gọi đầy đủ của các lệnh gọi lại JavaScript không đồng bộ!
Sau khi bật tính năng ngăn xếp lệnh gọi không đồng bộ trong Công cụ cho nhà phát triển, bạn sẽ có thể xem chi tiết trạng thái của ứng dụng web tại nhiều thời điểm tại nhiều thời điểm. Xem dấu vết ngăn xếp đầy đủ cho một số trình nghe sự kiện, setInterval
,setTimeout
, XMLHttpRequest
, lời hứa, requestAnimationFrame
, MutationObservers
và nhiều trình nghe khác.
Khi đi theo dấu vết ngăn xếp, bạn cũng có thể phân tích giá trị của mọi biến tại thời điểm thực thi trong thời gian chạy cụ thể đó. Nó giống như một cỗ máy thời gian cho các biểu thức đồng hồ!
Hãy bật tính năng này và xem một vài trường hợp sau.
Bật tính năng gỡ lỗi không đồng bộ trong Chrome
Hãy bật tính năng mới này trong Chrome để dùng thử. Chuyển đến bảng Nguồn của Công cụ cho nhà phát triển của Chrome Canary.
Bên cạnh bảng điều khiển Call Stack (Ngăn xếp lệnh gọi) ở bên phải, có một hộp đánh dấu mới cho chế độ "Async" (Không đồng bộ). Chọn hộp đánh dấu để bật hoặc tắt tính năng gỡ lỗi không đồng bộ. (Mặc dù sau khi bật, bạn có thể không bao giờ muốn tắt tính năng này.)
Ghi lại sự kiện bộ tính giờ bị trì hoãn và phản hồi XHR
Có thể bạn đã thấy tuỳ chọn này trước đây trong Gmail:
Nếu có sự cố khi gửi yêu cầu (máy chủ đang gặp sự cố hoặc có vấn đề về kết nối mạng ở phía máy khách), Gmail sẽ tự động thử gửi lại thư sau một thời gian chờ ngắn.
Để xem cách ngăn xếp lệnh gọi không đồng bộ có thể giúp chúng ta phân tích các sự kiện bộ tính giờ bị trễ và phản hồi XHR, tôi đã tạo lại quy trình đó bằng ví dụ mô phỏng Gmail. Bạn có thể tìm thấy mã JavaScript đầy đủ trong đường liên kết ở trên, nhưng quy trình như sau:
Bằng cách chỉ xem xét ngăn xếp lệnh gọi trong các phiên bản trước của Công cụ cho nhà phát triển, một điểm ngắt trong postOnFail()
sẽ cung cấp cho bạn một ít thông tin về nơi gọi postOnFail()
. Tuy nhiên, hãy xem sự khác biệt khi bật
các ngăn xếp không đồng bộ:
Khi bật ngăn xếp lệnh gọi không đồng bộ, bạn có thể xem toàn bộ ngăn xếp lệnh gọi để dễ dàng xem yêu cầu được bắt đầu từ submitHandler()
(xảy ra sau khi nhấp vào nút gửi) hay từ retrySubmit()
(xảy ra sau độ trễ setTimeout()
):
Xem biểu thức không đồng bộ
Khi bạn đi qua toàn bộ ngăn xếp lệnh gọi, các biểu thức đã theo dõi cũng sẽ cập nhật để phản ánh trạng thái tại thời điểm đó!
Đánh giá mã từ các phạm vi trước đây
Ngoài việc chỉ đơn giản là xem biểu thức, bạn có thể tương tác với mã từ các phạm vi trước đó ngay trong bảng điều khiển JavaScript của Công cụ cho nhà phát triển.
Hãy tưởng tượng bạn là Tiến sĩ Ai và bạn cần một chút trợ giúp để so sánh đồng hồ từ trước khi vào Tardis với "bây giờ". Từ bảng điều khiển Công cụ cho nhà phát triển, bạn có thể dễ dàng đánh giá, lưu trữ và tính toán các giá trị từ các điểm thực thi khác nhau.
Việc sử dụng Công cụ cho nhà phát triển để thao tác với biểu thức sẽ giúp bạn tiết kiệm thời gian không phải chuyển về mã nguồn, chỉnh sửa và làm mới trình duyệt.
Giải quyết lời hứa được xâu chuỗi
Nếu bạn cho rằng quy trình Gmail mô phỏng trước đó sẽ khó làm sáng tỏ nếu không bật tính năng ngăn xếp lệnh gọi không đồng bộ, thì bạn có thể tưởng tượng rằng với các luồng không đồng bộ phức tạp hơn như các lời hứa theo chuỗi không? Hãy cùng xem lại ví dụ cuối cùng trong hướng dẫn của Jake Archibald về Lời hứa với JavaScript.
Dưới đây là một ảnh động nhỏ về cách di chuyển ngăn xếp lệnh gọi trong ví dụ về async-best-example.html của Jake.
Nhận thông tin chi tiết về ảnh động trên web
Hãy cùng tìm hiểu kỹ hơn về kho lưu trữ HTML5Rocks. Bạn có nhớ Ảnh động nhanh hơn với requestAnimationFrame của Paul Lewis không?
Mở bản minh hoạ requestAnimationFrame và thêm một điểm ngắt ở đầu phương thức update() (khoảng dòng 874) của post.html. Với ngăn xếp lệnh gọi không đồng bộ, chúng tôi nhận được nhiều thông tin chi tiết hơn về requestAnimationFrame, bao gồm cả khả năng quay lại lệnh gọi lại sự kiện cuộn đã khởi tạo.
Theo dõi nội dung cập nhật của DOM khi sử dụng MutationObserver
MutationObserver
cho phép chúng ta quan sát những thay đổi trong DOM. Trong ví dụ đơn giản này,
khi bạn nhấp vào nút, một nút DOM mới sẽ được thêm vào <div class="rows"></div>
.
Thêm điểm ngắt trong nodeAdded()
(dòng 31) trong demo.html. Khi bật ngăn xếp lệnh gọi không đồng bộ, bạn hiện có thể đẩy ngăn xếp lệnh gọi quay lại addNode()
để đến sự kiện nhấp ban đầu.
Mẹo gỡ lỗi JavaScript trong ngăn xếp lệnh gọi không đồng bộ
Đặt tên cho hàm
Nếu có ý định chỉ định tất cả các lệnh gọi lại dưới dạng hàm ẩn danh, bạn nên đặt tên cho các lệnh gọi lại đó để dễ dàng xem ngăn xếp lệnh gọi hơn.
Ví dụ: dùng một hàm ẩn danh như sau:
window.addEventListener('load', function() {
// do something
});
Và đặt tên như windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
Khi sự kiện tải kích hoạt, sự kiện đó sẽ xuất hiện trong dấu vết ngăn xếp Công cụ cho nhà phát triển cùng với tên hàm thay vì nội dung khó hiểu "(hàm ẩn danh)". Điều này giúp bạn dễ dàng xem nhanh những gì đang diễn ra trong dấu vết ngăn xếp.
Khám phá thêm
Tóm lại, dưới đây là tất cả các lệnh gọi lại không đồng bộ mà trong đó Công cụ cho nhà phát triển sẽ hiển thị toàn bộ ngăn xếp lệnh gọi:
- Hẹn giờ:
Quay lại vị trí khởi động
setTimeout()
hoặcsetInterval()
. - XHRs: Quay lại nơi
xhr.send()
được gọi. - Khung ảnh động:
Quay lại vị trí gọi
requestAnimationFrame
. - Promise (Lời hứa): Quay lại nơi đã giải quyết lời hứa.
- Object.observe: Quay lại vị trí ban đầu lệnh gọi lại trình quan sát được liên kết.
- MutationObservers: Quay lại vị trí kích hoạt sự kiện trình quan sát đột biến.
- window.postMessage(): Xem qua các lệnh gọi nhắn tin trong quá trình.
- DataTransferItem.getAsString()
- FileSystem API
- IndexedDB
- WebSQL
- Sự kiện DOM đủ điều kiện thông qua
addEventListener()
: Quay lại vị trí kích hoạt sự kiện. Vì lý do hiệu suất, không phải sự kiện DOM nào cũng đủ điều kiện sử dụng tính năng ngăn xếp cuộc gọi không đồng bộ. Ví dụ về các sự kiện hiện có bao gồm: "scroll", "hashchange" và "selectionchange". - Sự kiện đa phương tiện qua
addEventListener()
: Quay lại nơi kích hoạt sự kiện. Các sự kiện đa phương tiện có sẵn bao gồm: sự kiện âm thanh và video (ví dụ: "phát", "tạm dừng", "tỷ lệ thay đổi"), sự kiện WebRTC MediaStreamTrackList (ví dụ: "addtrack", "removetrack") và sự kiện MediaSource (ví dụ: "sourceopen").
Việc có thể thấy toàn bộ dấu vết ngăn xếp của các lệnh gọi lại JavaScript cần giữ được những sợi tóc đó trên đầu của bạn. Tính năng này trong Công cụ cho nhà phát triển sẽ đặc biệt hữu ích khi có nhiều sự kiện không đồng bộ xảy ra có liên quan với nhau hoặc nếu một ngoại lệ chưa được nắm bắt được gửi từ trong một lệnh gọi lại không đồng bộ.
Hãy dùng thử trong Chrome. Nếu bạn có ý kiến phản hồi về tính năng mới này, hãy gửi phản hồi cho chúng tôi về công cụ theo dõi lỗi của Công cụ của Chrome cho nhà phát triển hoặc trong Nhóm Công cụ của Chrome cho nhà phát triển.