Thực thi tập lệnh sau khi trì hoãn cụ thể bằng JavaScript


189

Có phương thức JavaScript nào tương tự như jQuery delay()hay wait()(để trì hoãn việc thực thi tập lệnh trong một khoảng thời gian cụ thể) không?

Câu trả lời:


189

Có những điều sau đây:

setTimeout(function, milliseconds);

Hàm có thể được chuyển qua thời gian sau đó hàm sẽ được thực thi.

Xem: Phương pháp cửa sổsetTimeout() .


3
Đây không phải là một biểu thức được thực thi mà là một hàm. Câu trả lời của @Marius minh họa điều đó.
pedrofurla

117
Đây không phải là một sự chậm trễ, đó là một ngã ba. Độ trễ nên làm việc trong cùng một chủ đề.
DragonLord

13
Điều này sẽ ngay lập tức thực hiện chức năng. Để "làm việc" (không đồng bộ), nó phải được ghi là: setTimeout (function () {MethodToCall ();}, 1000);
Bernoulli IT

6
Tôi muốn chỉ ra rằng chúng ta đang nói về JavaScript; đưa ra các "luồng" hoặc nó sẽ hoạt động "đồng bộ" có thể đúng về mặt kỹ thuậtngữ nghĩa nhưng không thực sự phù hợp với bối cảnh của JavaScript, vì thực sự không có cách nào để đạt được độ trễ với một trong hai phương thức đó (bạn không ' t tạo "chủ đề" trong JS giống như bạn làm trong các ngôn ngữ khác). Ngoài ra, điều này sẽ không thực hiện ngay lập tức function_referencetrừ khi bạn bao gồm (). Tức function_referencelà chỉ có thế - một tài liệu tham khảo; đi vào function_reference()sẽ gọi hàm ngay lập tức.
Daniel Bullis

237

Chỉ cần thêm vào những gì mọi người khác đã nói về setTimeout: Nếu bạn muốn gọi một hàm với một tham số trong tương lai, bạn cần thiết lập một số lệnh gọi hàm ẩn danh.

Bạn cần truyền hàm dưới dạng đối số để nó được gọi sau. Trong thực tế điều này có nghĩa là không có dấu ngoặc phía sau tên. Sau đây sẽ gọi cảnh báo cùng một lúc và nó sẽ hiển thị 'Xin chào thế giới':

var a = "world";
setTimeout(alert("Hello " + a), 2000);

Để khắc phục điều này, bạn có thể đặt tên của một hàm (như Flubba đã làm) hoặc bạn có thể sử dụng một hàm ẩn danh. Nếu bạn cần truyền tham số, thì bạn phải sử dụng hàm ẩn danh.

var a = "world";
setTimeout(function(){alert("Hello " + a)}, 2000);
a = "Stack Overflow";

Nhưng nếu bạn chạy mã đó, bạn sẽ nhận thấy rằng sau 2 giây, cửa sổ bật lên sẽ thông báo 'Xin chào tràn chồng'. Điều này là do giá trị của biến a đã thay đổi trong hai giây đó. Để làm cho nó nói 'Xin chào thế giới' sau hai giây, bạn cần sử dụng đoạn mã sau:

function callback(a){
    return function(){
        alert("Hello " + a);
    }
}
var a = "world";
setTimeout(callback(a), 2000);
a = "Stack Overflow";

Nó sẽ đợi 2 giây và sau đó bật lên 'Xin chào thế giới'.


37

Chỉ cần mở rộng một chút ... Bạn có thể thực thi mã trực tiếp trong setTimeoutcuộc gọi, nhưng như @patrick nói, bạn thường chỉ định một hàm gọi lại, như thế này. Thời gian là mili giây

setTimeout(func, 4000);
function func() {
    alert('Do stuff here');
}

27

Nếu bạn thực sự muốn có delaychức năng chặn (đồng bộ) (cho bất cứ điều gì), tại sao không làm điều gì đó như thế này:

<script type="text/javascript">
    function delay(ms) {
        var cur_d = new Date();
        var cur_ticks = cur_d.getTime();
        var ms_passed = 0;
        while(ms_passed < ms) {
            var d = new Date();  // Possible memory leak?
            var ticks = d.getTime();
            ms_passed = ticks - cur_ticks;
            // d = null;  // Prevent memory leak?
        }
    }

    alert("2 sec delay")
    delay(2000);
    alert("done ... 500 ms delay")
    delay(500);
    alert("done");
</script>

2
Khó khăn với giải pháp này là nó chủ động sử dụng bộ xử lý, dẫn đến tăng mức sử dụng năng lượng và giảm tài nguyên có sẵn cho các luồng / quy trình khác (ví dụ: các tab khác, các chương trình khác). Ngược lại, chế độ ngủ tạm thời sử dụng tài nguyên hệ thống.
ramcdougal

1
tốt hơn là sử dụng Date.now () thay vì Date mới () và đừng nghĩ về rò rỉ bộ nhớ
WayFarer

1
Tất nhiên là cần nhiều CPU, nhưng để thử nghiệm nhanh và bẩn, nó hoạt động
Maris B.

Tôi muốn một phiên bản của nó không khóa luồng, vì vậy tôi có thể làm mới DOM trước khi delaying (để trả lời câu hỏi này ). Có cách nào để làm như vậy?
Gui Imamura

3
Một thói quen nhỏ gọn hơn: trì hoãn chức năng (ms) {var start_time = Date.now (); while (Date.now () - start_time <ms); }
Công tước

15

Bạn cần sử dụng setTimeout và truyền cho nó chức năng gọi lại. Lý do bạn không thể sử dụng chế độ ngủ trong javascript là vì bạn chặn toàn bộ trang không làm gì trong lúc này. Không phải là một kế hoạch tốt. Sử dụng mô hình sự kiện của Javascript và luôn vui vẻ. Đừng chiến đấu với nó!


2
Tuy nhiên, nó sẽ hữu ích cho mục đích thử nghiệm. Giống như trì hoãn việc gửi biểu mẫu trong vài giây để đánh giá các thay đổi của trang trước khi yêu cầu HTTP mới được thực hiện.
gấp rút

1
@rushinge sau đó đặt cuộc gọi lại để gửi biểu mẫu và vô hiệu hóa biểu mẫu mặc định gửi
Populus

1
Ý tưởng tồi là để lại một liên kết dưới dạng mã ... vì bây giờ nó không hoạt động.
Emmet Arries

1
Hoặc bạn biết, tôi chỉ có thể sửa nó.
Patrick

14

Bạn cũng có thể sử dụng window.setInterval () để chạy một số mã liên tục trong một khoảng thời gian thông thường.


2
setInterval () không nên được sử dụng thay vào đó nên sử dụng setTimeout
paul

9
setTimeout()làm một lần, setInterval()làm nhiều lần Nếu bạn muốn mã của bạn chạy cứ sau 5 giây, setInterval()được tạo cho công việc.
RCoup

11

Để thêm vào các ý kiến ​​trước đó, tôi muốn nói như sau:

Các setTimeout()hàm trong JavaScript không tạm dừng thực hiện các kịch bản cho mỗi gia nhập, mà chỉ nói với trình biên dịch để thực hiện đôi khi mã trong tương lai.

Không có chức năng nào thực sự có thể tạm dừng thực thi được tích hợp trong JavaScript. Tuy nhiên, bạn có thể viết hàm riêng thực hiện một vòng lặp vô điều kiện cho đến khi đạt được thời gian bằng cách sử dụng Date()hàm và thêm khoảng thời gian bạn cần.


11

Nếu bạn chỉ cần kiểm tra độ trễ, bạn có thể sử dụng:

function delay(ms) {
   ms += new Date().getTime();
   while (new Date() < ms){}
}

Và sau đó nếu bạn muốn trì hoãn trong 2 giây, bạn làm:

delay(2000);

Có thể không phải là tốt nhất cho sản xuất mặc dù. Thêm vào đó trong các ý kiến


@ U2744 SNOWFLAKE Bạn có thể thử và chính xác hơn một chút trong nhận xét của mình
Christoffer

1
Chà, đó là một vòng lặp bận rộn sẽ làm cạn kiệt pin của máy tính xách tay và các thiết bị di động khác, và có lẽ cũng ngăn giao diện người dùng phản hồi (hoặc thậm chí hiển thị).
Ry-

@ U2744SNOWFLAKE Làm cho ý nghĩa. Đã cập nhật câu trả lời, cho những gì tôi đã sử dụng chức năng này cho :)
Christoffer

2
Hoạt động đủ tốt trong phát triển cho một giải pháp nhanh & bẩn (và tạm thời).
HumanInDisguise

5

Tại sao bạn không thể đặt mã đằng sau một lời hứa? (gõ vào đỉnh đầu của tôi)

new Promise(function(resolve, reject) {
  setTimeout(resolve, 2000);
}).then(function() {
  console.log('do whatever you wanted to hold off on');
});


5

Câu trả lời đơn giản là:

setTimeout(
    function () {
        x = 1;
    }, 1000);

Hàm trên chờ trong 1 giây (1000 ms) sau đó đặt x thành 1. Rõ ràng đây là một ví dụ; bạn có thể làm bất cứ điều gì bạn muốn bên trong chức năng ẩn danh.


4

Tôi thực sự thích lời giải thích của Maurius (phản hồi được nâng cao nhất) với ba phương thức khác nhau để gọi setTimeout.

Trong mã của tôi, tôi muốn tự động điều hướng đến trang trước khi hoàn thành sự kiện lưu AJAX. Việc hoàn thành sự kiện lưu có một hình ảnh động nhỏ trong CSS cho thấy việc lưu đã thành công.

Trong mã của tôi, tôi tìm thấy một sự khác biệt giữa hai ví dụ đầu tiên:

setTimeout(window.history.back(), 3000);

Cái này không chờ thời gian chờ - back () được gọi gần như ngay lập tức bất kể số tôi đặt vào cho độ trễ.

Tuy nhiên, thay đổi điều này thành:

setTimeout(function() {window.history.back()}, 3000);

Điều này làm chính xác những gì tôi đã hy vọng.

Điều này không đặc trưng cho hoạt động back (), điều tương tự cũng xảy ra với alert(). Về cơ bản với việc alert()sử dụng trong trường hợp đầu tiên, thời gian trễ được bỏ qua. Khi tôi bỏ qua cửa sổ bật lên, hình ảnh động cho CSS tiếp tục.

Vì vậy, tôi muốn giới thiệu phương thức thứ hai hoặc thứ ba mà anh mô tả ngay cả khi bạn đang sử dụng các hàm dựng sẵn và không sử dụng các đối số.


1

Tôi đã có một số lệnh ajax tôi muốn chạy với độ trễ ở giữa. Đây là một ví dụ đơn giản về một cách để làm điều đó. Tôi đã chuẩn bị để bị xé vụn mặc dù cho cách tiếp cận độc đáo của tôi. :)

//  Show current seconds and milliseconds
//  (I know there are other ways, I was aiming for minimal code
//  and fixed width.)
function secs()
{
    var s = Date.now() + ""; s = s.substr(s.length - 5);
  return s.substr(0, 2) + "." + s.substr(2);
}

//  Log we're loading
console.log("Loading: " + secs());

//  Create a list of commands to execute
var cmds = 
[
    function() { console.log("A: " + secs()); },
    function() { console.log("B: " + secs()); },
    function() { console.log("C: " + secs()); },
    function() { console.log("D: " + secs()); },
    function() { console.log("E: " + secs()); },
  function() { console.log("done: " + secs()); }
];

//  Run each command with a second delay in between
var ms = 1000;
cmds.forEach(function(cmd, i)
{
    setTimeout(cmd, ms * i);
});

// Log we've loaded (probably logged before first command)
console.log("Loaded: " + secs());

Bạn có thể sao chép khối mã và dán nó vào cửa sổ giao diện điều khiển và xem một cái gì đó như:

Loading: 03.077
Loaded: 03.078
A: 03.079
B: 04.075
C: 05.075
D: 06.075
E: 07.076
done: 08.076

1

Giải pháp đơn giản nhất để gọi hàm của bạn bị trì hoãn là:

function executeWithDelay(anotherFunction) {
    setTimeout(anotherFunction, delayInMilliseconds);
}

0

chức năng trì hoãn:

/**
 * delay or pause for some time
 * @param {number} t - time (ms)
 * @return {Promise<*>}
 */
const delay = async t => new Promise(resolve => setTimeout(resolve, t));

sử dụng asyncchức năng bên trong :

await delay(1000);

-1

Như đã nói, setTimeout là đặt cược an toàn nhất của bạn
Nhưng đôi khi bạn không thể tách logic thành một hàm mới thì bạn có thể sử dụng Date.now () để nhận mili giây và tự mình trì hoãn ....

function delay(milisecondDelay) {
   milisecondDelay += Date.now();
   while(Date.now() < milisecondDelay){}
}

alert('Ill be back in 5 sec after you click OK....');
delay(5000);
alert('# Im back # date:' +new Date());

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.