2009-11-21 33 views
23

Giả sử tôi làmThời gian chờ bằng nhau có được thực hiện theo thứ tự trong Javascript không?

setTimeout(foo, 0); 

... 

setTimeout(bar, 0); 

Tôi có thể chắc chắn foo sẽ bắt đầu thực hiện trước khi thanh không? Điều gì sẽ xảy ra nếu thay vì 0 tôi sử dụng hết thời gian chờ là 1, 10 hoặc 100 cho thanh?

Thử nghiệm đơn giản cho thấy trong trường hợp giá trị thời gian chờ bằng nhau, các mục tiêu thời gian chờ được thực thi theo cùng thứ tự như chính setTimeouts, nhưng có an toàn khi dựa vào hành vi này không?

+0

Nếu bạn quan tâm đến thứ tự thực hiện , bạn có thể xem trang này http://www.onsip.com/blog/2012/06/29/avoiding-javascript-settimeout-and-setinterval-problems –

Trả lời

4

Tóm lại, đừng dựa vào nó. Hãy xem this.

Có rất nhiều thông tin trong con số này để tiêu hóa nhưng hiểu nó hoàn toàn sẽ cung cấp cho bạn một tốt hơn thực hiện thi JavaScript làm việc như thế nào không đồng bộ.

+7

Tôi không thấy gì trong bài viết đó mà là đúng về điểm. Câu hỏi đặt ra không phải là khi các hàm mục tiêu được thực hiện, đó là về thứ tự chúng được thực thi. – jkl

+1

Không tính theo thứ tự nghiêm ngặt, đó là điểm "không đồng bộ" trong bài viết nói trên. – jldupont

+4

Chắc chắn, sự chậm trễ thực tế có thể dài hơn mong đợi và khoảng thời gian hoạt động khác với giờ, nhưng bài viết không trực tiếp giải quyết câu hỏi. Bất kể nó mất 0 mili giây hoặc 100 năm để thực hiện 'foo', nó sẽ luôn luôn xảy ra trước' bar'? Hoặc trình duyệt có thể chọn tùy tiện không? Tôi cảm thấy như có phải là một tiêu chuẩn (hoặc ít nhất một số thông tin) về điều này. – Calvin

1

Có một mức tối thiểu nhất định là sự chậm trễ thực sự có thể và điều đó phụ thuộc rất nhiều vào hệ điều hành, trình duyệt, hoạt động trình duyệt và tải trên máy tính. Tôi có xu hướng không đi dưới 20ms khi tôi nghĩ rằng bất cứ điều gì ít hơn mà không làm cho bất kỳ sự khác biệt.

Khi bạn đặt hai độ trễ bằng nhau, điều đó không nhất thiết có nghĩa là nó sẽ xảy ra theo thứ tự đó.

Nếu bạn muốn đảm bảo rằng nó sẽ được thực hiện theo thứ tự tôi có xu hướng để làm một cái gì đó như thế này:

setTimeout(function() { 
    foo(); 
    setTimeout(bar, 20) 
}, 20); 

này sẽ luôn đảm bảo trật tự.

Nếu bạn đang sử dụng Firefox, để đảm bảo javascript của bạn thực sự đa luồng, bạn có thể muốn xem WebWorker, được hỗ trợ trên các trình duyệt mới hơn, nhưng không hỗ trợ IE.

+2

Bạn có biết một ví dụ cụ thể trong đó thời gian chờ bằng nhau được thực hiện không theo thứ tự? – jkl

+0

Tôi chỉ không tin tưởng tùy thuộc vào nó, khi nó quan trọng, như tôi đã không nhìn thấy bất cứ điều gì đảm bảo nó. –

+1

Độ trễ hữu ích "ngắn nhất" phụ thuộc vào tốc độ thực thi và tốc độ máy tính, nhưng "0" là thời gian hữu ích để sử dụng cho setTimeout, vì nó ngăn chặn lời gọi cho đến khi ngăn xếp cuộc gọi hiện tại bị xóa. – Nosredna

13

Tôi đọc qua mã nguồn của Firefox và ít nhất là đối với trình duyệt đó, có một sự đảm bảo tuần tự cho thời gian chờ được chỉ định trong thứ tự không thay đổi. Nếu không, tất cả các cược sẽ bị tắt.

Cụ thể, nếu trong ngữ cảnh thực thi cho trước, bạn đặt thời gian chờ cho n và sau đó cho m, trong đó n < = m, các mục tiêu sẽ được thực hiện theo thứ tự thời gian chờ đã được đặt.

Nhưng đừng dùng từ ngữ của tôi cho nó. Tôi tin rằng việc thực hiện cửa sổ là trong nsGlobalWindow.cpp, và phương pháp mà thực sự quyết định nơi timeouts đi trong hàng đợi thực hiện được gọi là InsertTimeoutIntoList. Dường như phương thức đi qua hàng đợi ngược lại tìm kiếm thời gian chờ đầu tiên nhỏ hơn hoặc bằng thời gian chờ đã cho và chèn thời gian chờ nhất định sau nó.

Tất nhiên khi hết thời gian chờ, thời gian đồng hồ hiện tại sẽ được thêm vào giá trị thời gian chờ. Đây là lý do tại sao các giá trị thời gian chờ phải nằm trong thứ tự giảm bậc cho các mục tiêu được thực thi theo thứ tự.

13

Không an toàn để dựa vào hành vi này. Tôi đã viết một kịch bản thử nghiệm lên lịch một số hàm (và lần lượt chúng cũng lên lịch một số hàm) tất cả sử dụng setTimeout (..., 0) và thứ tự mà các hàm được gọi không phải lúc nào cũng giống như thứ tự trong đó setTimeout được gọi là (ít nhất là trong Chrome 11, mà tôi đã sử dụng để chạy tập lệnh).

Bạn có thể xem/chạy tập lệnh tại đây: http://jsfiddle.net/se9Jn/ (tập lệnh sử dụng YUI cho khả năng tương thích trên nhiều trình duyệt, nhưng Y.later sử dụng setTimeout nội bộ).

Lưu ý rằng nếu bạn chỉ chạy tập lệnh và nhìn chằm chằm vào bảng điều khiển, có thể bạn sẽ không thấy thứ tự vi phạm. Nhưng nếu bắt đầu tập lệnh, hãy chuyển sang tab khác, tải một số trang và quay lại trang kiểm tra, bạn sẽ thấy lỗi về các cuộc gọi lại không đúng thứ tự trong bảng điều khiển.

Nếu bạn cần một trật tự được bảo đảm, tôi muốn giới thiệu lịch chức năng tiếp theo vào cuối của hàm theo thời gian:

setTimeout(foo, 0); 

... 

function foo() { 

    ... 

    setTimeout(bar, 0); 
} 
3

Câu trả lời là: Không, trình tự thực hiện không được bảo đảm. Thỉnh thoảng tôi thấy không đặt hàng FIFO trong chrome 40, đặc biệt nếu tôi tạm dừng trong trình gỡ lỗi trong khi thời gian chờ đang chờ xử lý. Tôi cũng có một cảnh tượng hiếm thấy trong tự nhiên - đó là lời giải thích hợp lý duy nhất về một sự cố mà tôi đã điều tra.

Nếu bạn cần để thực hiện đảm bảo, thay vì setTimeout(callback, 0) bạn có thể làm điều này:

var queue = []; 
function handleQueue() { 
    queue.shift()(); 
} 
function queueCallback(callback) { 
    queue.push(callback); 
    setTimeout(handleQueue, 0); 
} 

Bây giờ, cho bảo lãnh foo, bar để bạn có thể:

queueCallback(foo); 
... 
queueCallback(bar); 
Các vấn đề liên quan