Chào mừng bạn đến với Cafedev! Trong bài viết này, chúng ta sẽ khám phá cách JavaScript xử lý việc tải tài nguyên qua các sự kiện `onload` và `onerror`. Từ việc tải script đến các hình ảnh và iframe, hiểu rõ cách các sự kiện này hoạt động giúp bạn quản lý và xử lý tài nguyên một cách hiệu quả hơn trong các dự án web. Hãy cùng Cafedev tìm hiểu chi tiết và nâng cao kỹ năng JavaScript của bạn ngay hôm nay!

Trình duyệt cho phép chúng ta theo dõi việc tải các tài nguyên bên ngoài — script, iframe, hình ảnh và nhiều hơn nữa.
Có hai sự kiện cho việc này:

  • onload — tải thành công,
  • onerror — xảy ra lỗi.

1. Tải một script

Giả sử chúng ta cần tải một script từ bên thứ ba và gọi một hàm có trong đó.
Chúng ta có thể tải nó một cách động, như thế này:

let script = document.createElement('script');
script.src = "my.js";

document.head.append(script);

…Nhưng làm thế nào để gọi hàm được khai báo bên trong script đó? Chúng ta cần chờ cho đến khi script tải xong, và chỉ sau đó mới có thể gọi nó.
“`smart Đối với các script của riêng chúng ta, chúng ta có thể sử dụng JavaScript modules ở đây, nhưng chúng chưa được áp dụng rộng rãi bởi các thư viện bên thứ ba.

script.onload

Trợ giúp chính là sự kiện load. Nó được kích hoạt sau khi script đã được tải và thực thi.
Ví dụ:


let script = document.createElement('script');

// can load any script, from any domain
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
document.head.append(script);


script.onload = function() {
  // the script creates a variable "_"
  alert( _.VERSION ); // shows library version
};

Vậy trong onload, chúng ta có thể sử dụng các biến script, chạy các hàm, v.v.
…Còn nếu việc tải bị lỗi thì sao? Ví dụ, không có script đó (lỗi 404) hoặc máy chủ không hoạt động (không khả dụng).

script.onerror

Các lỗi xảy ra trong quá trình tải script có thể được theo dõi trong sự kiện error.
Ví dụ, hãy yêu cầu một script không tồn tại:

run
let script = document.createElement('script');
script.src = "https://example.com/404.js"; // no such script
document.head.append(script);


script.onerror = function() {
  alert("Error loading " + this.src); // Error loading https://example.com/404.js
};

Xin lưu ý rằng chúng ta không thể nhận được chi tiết lỗi HTTP ở đây. Chúng ta không biết đó là lỗi 404, 500 hay lỗi khác. Chỉ biết rằng việc tải đã thất bại.
``warn Các sự kiệnonload/onerror` chỉ theo dõi việc tải xuống chính.

Các lỗi có thể xảy ra trong quá trình xử lý và thực thi script nằm ngoài phạm vi của các sự kiện này. Cụ thể: nếu một script đã tải thành công, thì onload sẽ được kích hoạt, ngay cả khi nó có lỗi lập trình. Để theo dõi lỗi trong script, có thể sử dụng trình xử lý toàn cục window.onerror.

2. Các tài nguyên khác

Các sự kiện loaderror cũng hoạt động cho các tài nguyên khác, cơ bản là cho bất kỳ tài nguyên nào có src bên ngoài.
Ví dụ:


let img = document.createElement('img');
img.src = "https://js.cx/clipart/train.gif"; // (*)

img.onload = function() {
  alert(`Image loaded, size ${img.width}x${img.height}`);
};

img.onerror = function() {
  alert("Error occurred while loading image");
};

Tuy nhiên, có một số lưu ý:
– Hầu hết các tài nguyên bắt đầu tải khi chúng được thêm vào tài liệu. Nhưng là một ngoại lệ. Nó bắt đầu tải khi nó nhận được một src (*).
– Đối với , sự kiện iframe.onload được kích hoạt khi iframe hoàn tất việc tải, cả khi tải thành công và trong trường hợp có lỗi.
Điều này là do lý do lịch sử.

3. Chính sách Crossorigin

Có một quy tắc: các script từ một trang web không thể truy cập nội dung của trang web khác. Ví dụ, một script tại https://facebook.com không thể đọc hộp thư của người dùng tại https://gmail.com.
Hoặc, để chính xác hơn, một nguồn gốc (cặp miền/cổng/giao thức) không thể truy cập nội dung từ một nguồn gốc khác. Vì vậy, ngay cả khi chúng ta có một tên miền phụ hoặc chỉ là một cổng khác, đó là những nguồn gốc khác nhau không thể truy cập lẫn nhau.

Quy tắc này cũng ảnh hưởng đến các tài nguyên từ các miền khác.

Nếu chúng ta sử dụng một script từ miền khác, và có lỗi trong đó, chúng ta không thể nhận được chi tiết lỗi.

Ví dụ, hãy lấy một script error.js gồm một lệnh gọi hàm (xấu):

// 📁 error.js
noSuchFunction();

Bây giờ tải nó từ cùng một trang web nơi nó được lưu trữ:


<script>
window.onerror = function(message, url, line, col, errorObj) {
  alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="/article/onload-onerror/crossorigin/error.js"></script>

Chúng ta có thể thấy một báo cáo lỗi tốt, như sau:
Uncaught ReferenceError: noSuchFunction is not defined https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1
Bây giờ hãy tải cùng một script từ miền khác:


<script>
window.onerror = function(message, url, line, col, errorObj) {
  alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>

Báo cáo sẽ khác, như thế này:

Script error.
, 0:0


Các chi tiết có thể khác nhau tùy thuộc vào trình duyệt, nhưng ý tưởng là như nhau: bất kỳ thông tin nào về cấu trúc bên trong của một kịch bản, bao gồm cả các dấu vết lỗi, đều bị ẩn. Chính xác vì lý do nó đến từ miền khác

Tại sao chúng ta cần thông tin chi tiết về lỗi?

Có nhiều dịch vụ (và chúng ta có thể xây dựng dịch vụ của riêng mình) lắng nghe các lỗi toàn cầu bằng cách sử dụng window.onerror, lưu trữ lỗi và cung cấp giao diện để truy cập và phân tích chúng. Điều đó rất tuyệt vời, vì chúng ta có thể thấy các lỗi thực tế, được kích hoạt bởi người dùng của chúng ta. Nhưng nếu một kịch bản đến từ nguồn gốc khác, thì sẽ không có nhiều thông tin về lỗi trong đó, như chúng ta vừa thấy.

Chính sách cross-origin tương tự (CORS) cũng được áp dụng cho các loại tài nguyên khác.

Để cho phép truy cập xuyên nguồn (cross-origin), thẻ <script> cần có thuộc tính crossorigin, và máy chủ từ xa phải cung cấp các tiêu đề đặc biệt.

Có ba cấp độ truy cập xuyên nguồn:

  1. Không có thuộc tính crossorigin – Truy cập bị cấm.
  2. crossorigin="anonymous" – Truy cập được phép nếu máy chủ phản hồi với tiêu đề Access-Control-Allow-Origin với giá trị là * hoặc nguồn gốc của chúng ta. Trình duyệt không gửi thông tin xác thực và cookie đến máy chủ từ xa.
  3. crossorigin="use-credentials" – Truy cập được phép nếu máy chủ gửi lại tiêu đề Access-Control-Allow-Origin với nguồn gốc của chúng ta và Access-Control-Allow-Credentials: true. Trình duyệt gửi thông tin xác thực và cookie đến máy chủ từ xa.

Bạn có thể tìm hiểu thêm về truy cập xuyên nguồn trong chương Fetch: Cross-Origin Requests. Chương này mô tả phương thức fetch cho các yêu cầu mạng, nhưng chính sách là hoàn toàn giống nhau.

Vấn đề về “cookie” nằm ngoài phạm vi của chúng ta hiện tại, nhưng bạn có thể đọc về chúng trong chương Cookies, document.cookie.

Trong trường hợp của chúng ta, chúng ta không có thuộc tính crossorigin. Vì vậy, truy cập xuyên nguồn bị cấm. Hãy thêm thuộc tính này.

Chúng ta có thể chọn giữa “anonymous” (không gửi cookie, cần một tiêu đề máy chủ) và “use-credentials” (cũng gửi cookie, cần hai tiêu đề máy chủ).

Nếu chúng ta không quan tâm đến cookie, thì “anonymous” là lựa chọn tốt:

<script>
window.onerror = function(message, url, line, col, errorObj) {
  alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script crossorigin="anonymous" src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>

Bây giờ, giả sử máy chủ cung cấp tiêu đề Access-Control-Allow-Origin, mọi thứ đều ổn. Chúng ta có báo cáo lỗi đầy đủ.

4. Tóm tắt

Các phần tử như <img>, các kiểu dáng bên ngoài, tập lệnh và các tài nguyên khác cung cấp các sự kiện tải và lỗi để theo dõi việc tải:

  • load kích hoạt khi tải thành công,
  • error kích hoạt khi tải thất bại.

Ngoại lệ duy nhất là <iframe>: vì lý do lịch sử, nó luôn kích hoạt sự kiện load cho mọi hoàn tất tải, ngay cả khi trang không được tìm thấy.

Sự kiện readystatechange cũng hoạt động cho các tài nguyên, nhưng hiếm khi được sử dụng, vì các sự kiện load/error đơn giản hơn.

Chào mừng bạn đến với Cafedev! Trong bài viết này, chúng ta sẽ khám phá cách JavaScript xử lý việc tải tài nguyên qua các sự kiện `onload` và `onerror`. Từ việc tải script đến các hình ảnh và iframe, hiểu rõ cách các sự kiện này hoạt động giúp bạn quản lý và xử lý tài nguyên một cách hiệu quả hơn trong các dự án web. Hãy cùng Cafedev tìm hiểu chi tiết và nâng cao kỹ năng JavaScript của bạn ngay hôm nay!

Tham khảo thêm: MIỄN PHÍ 100% | Series tự học Javascrypt chi tiết, dễ hiểu từ cơ bản tới nâng cao + Full Bài Tập thực hành nâng cao trình dev

Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của CafeDev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!