2011-11-26 40 views
6

Tôi có chức năng không đồng bộ mà tôi muốn có độ trễ 5000ms trước khi bị kích hoạt. Tôi đang cố gắng sử dụng setTimeout() để đạt được điều này. Hàm async này xảy ra trong một vòng lặp chạy nhiều lần, với hàm async được truyền dữ liệu khác nhau mỗi lần, do đó không thể sử dụng setInterval() ở đây.setTimeout trên chức năng không đồng bộ

Vấn đề: Chức năng async được kích hoạt ngay lập tức mà không chậm trễ (console in 5 Done điệp instantly` và lặp mà không dán đoạn gì đã xảy ra, và làm thế nào tôi có thể giải quyết nó

Javascript Mã

.?
someFunction(listings, function() { 
    for (var i in listings) { 
     var listing = listings[i]; 
     setTimeout(asyncFunction(listing, function(data) { 
      console.log('Done'); 
     }), 5000); 
    } 
}); 
+0

Nếu "danh sách" thực sự là mảng, bạn không nên lặp lại bằng "cho ... trong". Sử dụng chỉ mục số thay thế. – Pointy

+0

@Pointy Có nó chỉ là một mảng, oops :) – Nyxynyx

Trả lời

9

Bạn phải bọc hàm trong một hàm khác. Hiện tại, bạn đang gọi hàm và chuyển giá trị trả về làm đối số cho setTimeout. tly) chuyển một hàm đến setTimeout. Sau 5 giây, hàm sẽ thực thi.

Tôi phải thêm hai chức năng để đạt được hành vi mong muốn, do các vấn đề về phạm vi. Sau 5 giây, vòng lặp đã kết thúc và biến số listing sẽ bằng với phần tử cuối cùng trong listings.

someFunction(listings, function() { 
    var counter = 0; // Define counter for 5 second-delays between each call 
    for (var i in listings) { 
     var listing = listings[i]; 
     (function(listing){ //Closure function 
      setTimeout(function(){ //setTimeout function 
       // Because of the closure, `listing` is unique 
       asyncFunction(listing, function(a, b) { 
        console.log('Done'); 
       }); 
      }, 5000 * ++counter); //Increase counter for each loop 
     })(listing); 
    } 
}); 
+0

điều này sẽ vẫn kích hoạt n timeouts gần như song song. – jAndy

+0

Cảm ơn bạn đã trả lời! Có độ trễ 5000ms ban đầu, nhưng các cuộc gọi tiếp theo đến asyncFunction xảy ra ngay lập tức! Các cuộc gọi tiếp theo với các chức năng có sự chậm trễ sao cho mỗi cuộc gọi đều cách nhau 5000ms? – Nyxynyx

+0

nó cũng có vấn đề về vòng lặp/phạm vi cổ điển (biến "liệt kê") – Pointy

-1

đó là điểm khác biệt. Điểm chính là asyncFunction làm gì? bạn có thể dán nó ra không?

var foo=function(){ 
    alert("BAR"); 
    return function(){ 
     alert("I AM!"); 
    }; 
} 
setTimeout(foo(),4000); 
setTimeout(foo,5000); 
+4

"setTimeout()" đầu tiên không chính xác, vì nó sẽ ngay lập tức gọi "foo()" và chuyển kết quả * của nó * đến "setTimeout()". Thứ hai, đi qua một chuỗi, thường được coi là không được chấp nhận. – Pointy

+0

có, chuỗi đi qua sẽ 'eval' và sau đó chạy nó trên phạm vi toàn cầu. Ý tưởng rất xấu – Rifat

+0

cảm ơn bạn rất nhiều! – island205

1

Không biết asyncFunction của bạn có vẻ như chỉ đơn giản trả về hàm bạn đã vượt qua.

someFunction(listings, function() { 
    for (var i = 0; i < listings.length; ++i) { 
     setTimeout(asyncFunction(listings[i], function(data) { 
      console.log('Done'); 
     }), 5000 * i); 
    } 
}); 

function asyncFunction(lstng, func) { 
    return func; 
} 

Mặc dù tôi hy vọng rằng bạn cần kết thúc một số logic bổ sung.

function asyncFunction(lstng, func) { 
    return function() { 
     // do some stuff with the listing 

     // then invoke the func 
     func(); 
    } 
} 

Bây giờ asyncFunction kết thúc tốt đẹp của bạn bất cứ điều gì là cần thiết trong một chức năng mới được trả lại cho setTimeout. Hàm mới cũng gọi ra gọi lại mà bạn đã chuyển.


JSFIDDLE DEMO

+0

Cảm ơn, đã giảm dòng mã bằng cách sử dụng 'i' thay vì' truy cập'. asyncFunction sử dụng 2 giá trị gọi lại bên trong 'dữ liệu' và gửi chúng đến một máy chủ khác. – Nyxynyx

+0

@Nyxynyx: Không hoàn toàn chắc chắn ý bạn là gì, nhưng bạn có thể chuyển bất kỳ thứ gì bạn cần cho hàm gọi lại. Điểm chính của tôi là bạn đã có một hàm được đặt tên, do đó không cần phải thêm hai cấp độ nội tuyến. Bạn chỉ cần sửa đổi 'asyncFunction' để nó * trả về * một hàm được gọi bởi 'setTimeout'. Đây là một cách tiếp cận rõ ràng hơn. – RightSaidFred

4

Nếu bạn đang sử dụng ECMAScript6 bạn có thể sử dụng Promise.

Vì vậy, tạo một hàm sự chậm trễ đó quấn cuộc gọi đến setTimeout thành một Promise:

function delay(ms) { 
    return new Promise(function (resolve) { return setTimeout(resolve, ms); }); 
}; 

Và bạn có thể sử dụng nó như thế:

someFunction(listings, function() { 
    for (var i in listings) { 
     var listing = listings[i]; 
     delay(5000).then(() => { 
      return asyncFunction(listing); 
     }).then(() => { 
      console.log('Done'); 
     }); 
    } 
}); 

Nếu bạn đang sử dụng ECMAScript 2017 bạn có thể sử dụng aync/await.

Hàm không đồng bộ trả về lời hứa để bạn không phải thay đổi mã của hàm chậm trễ.

async someFunction(listings, function() { 
    for (var i in listings) { 
     var listing = listings[i]; 
     await delay(5000); 
     await asyncFunction(listing); 
     console.log('Done'); 
    } 
}); 
Các vấn đề liên quan