2012-01-31 31 views
28

Khá thường xuyên nhìn thấy trong mã JavaScript thư viện như thế này:Gọi setTimeout không chậm trễ

setTimeout(function() { 
    ... 
}, 0); 

Tôi muốn biết tại sao sử dụng như một mã wrapper.

+5

** M PROO CHUYÊN NGHIỆP: ** Bạn không cần ', 0' ở cuối. – vsync

Trả lời

40

Rất đơn giản:

Các trình duyệt độc thân ren và sợi đơn này (The thread UI) được chia sẻ giữa các công cụ rendering và động cơ js.

Nếu điều bạn muốn làm mất nhiều thời gian (chúng tôi nói về chu kỳ ở đây nhưng vẫn) nó có thể tạm dừng (tạm dừng) kết xuất (dòng và sơn).

Trong trình duyệt cũng có "Thùng", nơi tất cả các sự kiện được đặt trước để đợi cho chuỗi giao diện người dùng được thực hiện với bất kỳ thao tác nào đang thực hiện. Ngay sau khi các chủ đề được thực hiện nó trông trong xô và chọn nhiệm vụ đầu tiên trong dòng.

Sử dụng setTimeout bạn tạo một tác vụ mới trong nhóm sau khi trì hoãn và để chuỗi xử lý ngay sau khi nó có sẵn để có thêm công việc.

Một câu chuyện:

Sau 0 ms trì hoãn tạo ra một nhiệm vụ mới của hàm và đặt nó trong xô. Vào thời điểm chính xác, chuỗi giao diện người dùng bận đang bận làm điều gì đó khác và có một nhiệm vụ khác trong thùng rồi. Sau 6ms, chuỗi có sẵn và nhận được thông tin về nhiệm vụ của bạn, tốt, bạn sắp tới. Nhưng cái gì? Đó là một điều rất lớn! Nó có giống như foreeeeeever (30ms) !!

Cuối cùng, bây giờ, chuỗi được thực hiện với điều đó và đến và nhận nhiệm vụ của bạn.

Hầu hết các trình duyệt đều có độ trễ tối thiểu bằng 0, vì vậy đặt 0 làm chậm trễ có nghĩa là: Đặt tác vụ này vào giỏ ASAP. Nhưng nói với UA để đặt nó trong xô ASAP là không đảm bảo nó sẽ thực hiện tại thời điểm đó. Thùng giống như bưu điện, có thể là có hàng đợi dài các nhiệm vụ khác. Bưu điện cũng là đơn luồng với chỉ một người giúp mọi công việc ...xin lỗi khách hàng với nhiệm vụ của họ. Nhiệm vụ của bạn phải xếp hàng như mọi người khác.

Nếu trình duyệt không triển khai mã đánh dấu riêng, trình duyệt sẽ sử dụng các chu kỳ đánh dấu của hệ điều hành. Các trình duyệt cũ hơn có độ trễ tối thiểu từ 10-15ms. HTML5 specifies nếu độ trễ nhỏ hơn 4ms thì UA sẽ tăng lên 4ms. Điều này được gọi là consistent across browsers released in 2010 and onward.

Xem How JavaScript Timers Work bởi John Resig để biết thêm chi tiết.

Chỉnh sửa: Cũng xem What the heck is the event loop anyway? bởi Philip Roberts từ JSConf EU 2014. Đây là bắt buộc xem cho tất cả mọi người chạm vào mã front-end.

1

Để cho phép bất kỳ thời gian chờ nào được đặt trước đó thực thi.

7

Có một vài lý do tại sao bạn nên làm việc này

  • Có một hành động mà bạn không muốn chạy ngay lập tức nhưng muốn chạy tại một số khoảng thời gian gần trong tương lai.
  • Bạn muốn cho phép xử lý đăng ký trước đây khác từ một setTimeout hoặc setInterval để chạy
3

Khi bạn muốn thực hiện phần còn lại của mã của bạn mà không cần chờ đợi trước đó để kết thúc bạn cần phải thêm nó trong phương thức nặc danh thông qua với setTimeout chức năng. Nếu mã của bạn sẽ đợi cho đến khi trước đó được thực hiện

Ví dụ:

function callMe() 
{ 
    for(var i = 0; i < 100000; i++) 
    { 
     document.title = i; 
    } 
} 

var x = 10; 
setTimeout(callMe, 0); 

var el = document.getElementById('test-id'); 
el.innerHTML = 'Im done before callMe method'; 

Đó là lý do tôi sử dụng nó.

6

Ngoài các câu trả lời trước đây, tôi muốn thêm một kịch bản hữu ích khác mà tôi có thể nghĩ đến: để "thoát" khỏi khối try-catch. Một setTimeout-delay từ bên trong khối try-catch sẽ được thực hiện bên ngoài khối và bất kỳ ngoại lệ nào sẽ lan truyền trong phạm vi toàn cục thay thế.

Có lẽ ví dụ điển hình nhất: Trong JavaScript ngày nay, việc sử dụng phổ biến hơn được gọi là Trì hoãn/Hứa hẹn cho các cuộc gọi lại không đồng bộ, bạn thường (thực sự) chạy bên trong try-catch. Trì hoãn/Lời hứa bọc gọi lại trong một lần thử để có thể phát hiện và truyền bá ngoại lệ dưới dạng lỗi trong chuỗi không đồng bộ. Điều này là tốt cho các chức năng cần có trong chuỗi, nhưng sớm hay muộn bạn đã "thực hiện" (tức là lấy tất cả ajax của bạn) và muốn chạy mã không đồng bộ không đồng bộ nơi bạn không muốn ngoại lệ là " ẩn "nữa. Dojo AFAIK, Q, MochiKit và Google Closure lib của Kris Kowal sử dụng gói try-catch (Không phải jQuery).

(Đôi khi tôi cũng sử dụng kỹ thuật này để khởi động lại mã kiểu Singleton mà không gây đệ quy. Tôi đang thực hiện khởi động lại trong cùng một vòng lặp).

Các vấn đề liên quan