Tìm hiểu chi tiết về trình duyệt web hiện đại (phần 4)

Mariko Kosaka

Dữ liệu đầu vào sắp xuất hiện trên Trình tổng hợp

Đây là phần cuối trong loạt blog gồm 4 phần về bên trong Chrome; điều tra cách nó xử lý mã của chúng tôi để hiển thị trang web. Trong bài đăng trước, chúng ta đã xem xét quy trình kết xuất và tìm hiểu về trình tổng hợp. Trong bài đăng này, chúng tôi sẽ xem xét cách trình tổng hợp cho phép tương tác mượt mà khi người dùng có hoạt động đầu vào.

Nhập sự kiện từ góc nhìn của trình duyệt

Khi bạn nghe thấy "sự kiện nhập" bạn có thể chỉ nghĩ đến việc nhập vào hộp văn bản hoặc nhấp chuột, nhưng từ quan điểm của trình duyệt, dữ liệu nhập có nghĩa là bất kỳ cử chỉ nào của người dùng. Cuộn con lăn chuột là một phương thức nhập sự kiện và chạm hoặc di chuột qua cũng là một sự kiện đầu vào.

Khi cử chỉ của người dùng như chạm vào màn hình diễn ra, quá trình của trình duyệt là quá trình nhận cử chỉ đầu tiên. Tuy nhiên, quá trình xử lý của trình duyệt chỉ biết được vị trí cử chỉ đó diễn ra kể từ nội dung bên trong một thẻ được xử lý bởi quá trình kết xuất đồ hoạ. Vì vậy, quy trình của trình duyệt sẽ gửi sự kiện loại (như touchstart) và các toạ độ của nó vào quy trình kết xuất. Quá trình kết xuất xử lý một cách thích hợp bằng cách tìm mục tiêu sự kiện và chạy trình nghe sự kiện được đính kèm.

sự kiện nhập
Hình 1: Sự kiện đầu vào được định tuyến thông qua quy trình của trình duyệt đến quy trình kết xuất

Trình tổng hợp nhận sự kiện nhập

Hình 2: Khung nhìn di chuột trên các lớp trang

Trong bài đăng trước, chúng ta đã xem xét cách trình tổng hợp có thể xử lý thao tác cuộn suôn sẻ bằng cách tổng hợp các lớp đã tạo điểm ảnh. Nếu không có trình nghe sự kiện đầu vào nào được đính kèm vào trang, thì luồng trình tổng hợp có thể tạo một khung tổng hợp mới hoàn toàn độc lập với luồng chính. Nhưng nếu một số sự kiện người nghe có được tương tác với trang không? Làm cách nào để trình tổng hợp tìm hiểu xem sự kiện đó có cần cần xử lý không?

Tìm hiểu về khu vực không thể cuộn nhanh

Vì chạy JavaScript là công việc của luồng chính, nên khi một trang được kết hợp, luồng trình tổng hợp đánh dấu một vùng của trang có trình xử lý sự kiện được đính kèm là "Khu vực không thể cuộn nhanh". Theo khi có thông tin này, luồng trình tổng hợp có thể đảm bảo gửi sự kiện đầu vào đến luồng chính nếu sự kiện xảy ra ở khu vực đó. Nếu sự kiện đầu vào đến từ bên ngoài khu vực này, thì luồng trình tổng hợp tiến hành quá trình tổng hợp khung mới mà không cần đợi luồng chính.

khu vực không thể cuộn nhanh bị giới hạn
Hình 3: Sơ đồ đầu vào được mô tả cho khu vực không thể cuộn nhanh

Hãy lưu ý khi bạn viết trình xử lý sự kiện

Một mẫu xử lý sự kiện phổ biến trong quá trình phát triển web là uỷ quyền sự kiện. Vì bong bóng sự kiện, bạn có thể đính kèm một trình xử lý sự kiện ở phần tử trên cùng và uỷ quyền các tác vụ dựa trên mục tiêu sự kiện. Bạn có thể đã xem hoặc viết mã như dưới đây.

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault();
    }
});

Vì bạn chỉ cần viết một trình xử lý sự kiện cho tất cả các phần tử, nên thông qua sự kiện này, bạn sẽ thấy mẫu uỷ quyền hấp dẫn. Tuy nhiên, nếu bạn xem mã này từ góc nhìn của trình duyệt chế độ xem, giờ đây, toàn bộ trang được đánh dấu là một khu vực không thể cuộn nhanh. Điều này có nghĩa là ngay cả khi ứng dụng không quan tâm đến dữ liệu đầu vào từ một số phần nhất định của trang, luồng của trình tổng hợp phải giao tiếp với luồng chính và chờ luồng này mỗi khi có sự kiện đầu vào. Do đó, khả năng cuộn mượt mà của trình tổng hợp bị đánh bại.

khu vực không thể cuộn nhanh toàn trang
Hình 4: Sơ đồ đầu vào được mô tả cho khu vực không thể cuộn nhanh bao gồm toàn bộ một trang

Để giảm thiểu điều này, bạn có thể truyền các lựa chọn passive: true vào sự kiện của mình trình nghe. Điều này sẽ gợi ý cho trình duyệt biết rằng bạn vẫn muốn nghe sự kiện trong luồng chính, nhưng trình tổng hợp cũng có thể tiếp tục và kết hợp khung mới.

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});

Kiểm tra xem sự kiện có thể huỷ hay không

cuộn trang
Hình 5: Một trang web có một phần của trang được cố định theo dạng cuộn ngang

Giả sử bạn có một hộp trong trang mà bạn muốn giới hạn hướng cuộn thành chỉ cuộn ngang.

Khi bạn sử dụng tuỳ chọn passive: true trong sự kiện con trỏ, quá trình cuộn trang có thể mượt mà, nhưng thao tác cuộn dọc có thể đã bắt đầu vào thời điểm bạn muốn preventDefault để giới hạn hướng cuộn. Bạn có thể kiểm tra lại bằng cách sử dụng phương thức event.cancelable.

document.body.addEventListener('pointermove', event => {
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});

Ngoài ra, bạn có thể sử dụng quy tắc CSS như touch-action để loại bỏ hoàn toàn trình xử lý sự kiện.

#area {
  touch-action: pan-x;
}

Tìm mục tiêu sự kiện

thử nghiệm nhấn
Hình 6: Luồng chính xem bản ghi sơn hỏi nội dung được vẽ trên điểm x.y

Khi luồng trình tổng hợp gửi một sự kiện đầu vào đến luồng chính, mục đầu tiên để chạy là một lượt truy cập thử nghiệm để tìm mục tiêu sự kiện. Kiểm tra lượt truy cập sử dụng dữ liệu bản ghi vẽ được tạo trong quá trình kết xuất để tìm ra nội dung bên dưới toạ độ điểm mà sự kiện đã xảy ra.

Giảm thiểu việc gửi sự kiện đến luồng chính

Trong bài đăng trước, chúng ta đã thảo luận về cách màn hình thông thường làm mới màn hình 60 lần mỗi giây và chúng tôi cần bắt kịp nhịp độ để hoạt ảnh mượt mà. Để nhập thông tin, màn hình cảm ứng thông thường thì thiết bị thực hiện thao tác chạm từ 60 đến 120 lần một giây, còn một con chuột thông thường thực hiện thao tác chạm 100 lần trong một khoảng thời gian. giây. Sự kiện đầu vào có độ trung thực cao hơn mức mà màn hình của chúng ta có thể làm mới.

Nếu một sự kiện liên tục như touchmove được gửi đến luồng chính 120 lần/giây, thì sự kiện đó có thể kích hoạt quá nhiều lần kiểm tra lần truy cập và thực thi JavaScript so với việc màn hình có thể làm mới.

sự kiện chưa được lọc
Hình 7: Các sự kiện làm ngập dòng thời gian của khung hình gây ra tình trạng giật trang

Để giảm thiểu số lệnh gọi quá nhiều đến luồng chính, Chrome sẽ tổng hợp các sự kiện liên tục (chẳng hạn như wheel, mousewheel, mousemove, pointermove, touchmove ) và trì hoãn việc gửi hàng cho đến ngay trước requestAnimationFrame tiếp theo.

sự kiện liên kết
Hình 8: Tiến trình giống như trước nhưng sự kiện được hợp nhất và bị trì hoãn

Mọi sự kiện rời rạc như keydown, keyup, mouseup, mousedown, touchstarttouchend được gửi đi ngay lập tức.

Sử dụng getCoalescedEvents để nhận các sự kiện trong khung hình

Đối với hầu hết các ứng dụng web, các sự kiện được kết hợp là đủ để cung cấp trải nghiệm người dùng tốt. Tuy nhiên, nếu bạn đang tạo những nội dung như vẽ ứng dụng và đặt đường dẫn dựa trên touchmove toạ độ, bạn có thể mất các toạ độ ở giữa để vẽ một đường thẳng. Trong trường hợp đó, bạn có thể dùng phương thức getCoalescedEvents trong sự kiện con trỏ để lấy thông tin về sự kiện được liên kết.

getCoalescedEvents
Hình 9: Đường dẫn cử chỉ chạm mượt mà ở bên trái, đường dẫn giới hạn được hợp nhất ở bên phải
window.addEventListener('pointermove', event => {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
});

Các bước tiếp theo

Trong loạt bài này, chúng tôi đã đề cập đến hoạt động bên trong trình duyệt web. Nếu bạn chưa từng nghĩ về lý do Công cụ cho nhà phát triển đề xuất thêm {passive: true} trên trình xử lý sự kiện hoặc lý do bạn có thể ghi async trong thẻ tập lệnh của mình, tôi hy vọng loạt video này sẽ làm sáng tỏ lý do tại sao một trình duyệt cần những để mang lại trải nghiệm web nhanh và mượt mà hơn.

Dùng Lighthouse

Nếu bạn muốn làm cho mã phù hợp với trình duyệt nhưng không biết bắt đầu từ đâu, Lighthouse là một công cụ chạy quy trình kiểm tra bất kỳ trang web nào và cung cấp cho bạn báo cáo về những nội dung cần cải thiện và những nội dung cần cải thiện. Đọc danh sách các cuộc kiểm tra cũng giúp bạn biết được những điều mà một trình duyệt quan tâm.

Tìm hiểu cách đo lường hiệu suất

Các nội dung điều chỉnh về hiệu suất có thể khác nhau tuỳ theo trang web, vì vậy, bạn cần phải đo lường hiệu suất của trang web rồi quyết định điều gì là phù hợp nhất với trang web của bạn. Nhóm Công cụ của Chrome cho nhà phát triển có một số hướng dẫn về cách đo lường hiệu suất của trang web.

Thêm Chính sách tính năng vào trang web

Nếu bạn muốn thực hiện thêm một bước, Chính sách tính năng là nền tảng web có thể là rào chắn cho bạn khi xây dựng dự án. Đang bật chính sách về tính năng đảm bảo một số hành vi nhất định của ứng dụng và giúp bạn không mắc sai lầm. Ví dụ: Nếu muốn đảm bảo ứng dụng của mình sẽ không bao giờ chặn quá trình phân tích cú pháp, bạn có thể chạy ứng dụng trên chính sách tập lệnh đồng bộ. Khi bạn bật sync-script: 'none', tính năng chặn trình phân tích cú pháp JavaScript sẽ không được thực thi. Thao tác này ngăn mọi mã của bạn chặn trình phân tích cú pháp và trình duyệt của bạn không cần phải lo lắng về việc tạm dừng trình phân tích cú pháp.

Tóm tắt

cảm ơn bạn

Khi bắt đầu xây dựng trang web, tôi hầu như chỉ quan tâm đến cách viết mã và những gì sẽ giúp tôi làm việc hiệu quả hơn. Những điều đó rất quan trọng, nhưng chúng ta cũng nên suy nghĩ về trình duyệt lấy mã chúng tôi viết. Các trình duyệt hiện đại đã và đang tiếp tục đầu tư vào cách mang lại trải nghiệm web tốt hơn cho người dùng. Đối xử tốt với trình duyệt bằng cách sắp xếp mã của chúng tôi, từ đó, cải thiện trải nghiệm người dùng. Tôi hy vọng bạn sẽ cùng tôi tham gia nhiệm vụ trở nên thân thiện với trình duyệt!

Rất cảm ơn những người đã đánh giá các bản nháp ban đầu của loạt video này, bao gồm (nhưng không giới hạn) đến): Alex Russell, Paul Ai-len, Meggin Kearney thân mến! Eric Bidelman, Mathias Bynens thân mến! Addy Osmani, Kinuko Yasuda, Nasko Oskov, và Charlie Reis.

Bạn có thích chuỗi video này không? Nếu bạn có câu hỏi hoặc đề xuất cho bài đăng trong tương lai, Tôi muốn nghe ý kiến của bạn trong phần bình luận bên dưới hoặc @kosamari trên Twitter.