2013-03-28 44 views
9

Tôi hơi bối rối về cách hoạt động của setTimeout. Tôi đang cố gắng để có một setTimeout trong một vòng lặp, để lặp lại vòng lặp được, nói, 1s ngoài. Mỗi vòng lặp lặp lại thực hiện một yêu cầu HTTP và có vẻ như máy chủ ở đầu kia không thể xử lý nhiều yêu cầu trong một khoảng thời gian ngắn như vậy.setTimeout trong vòng lặp Node.js

for (var i = 1; i<=2000 && ok; i++) { 
    var options = { 
     host:'www.host.com', 
     path:'/path/'+i 
    }; 

    setTimeout(makeRequest(options, i), 1000); 
}; 

Tại sao điều này không hoạt động và làm cách nào tôi có thể đạt được điều này?

Cảm ơn bạn

Trả lời

6

Bạn cần một cái gì đó như thế này

var counter = 5; 

function makeRequst(options, i) { 
    // do your request here 
} 

function myFunction() { 
    alert(counter); 

    // create options object here 
    //var options = { 
    // host:'www.host.com', 
    // path:'/path/'+counter 
    //}; 
    //makeRequest(options, counter); 

    counter--; 
    if (counter > 0) { 
     setTimeout(myFunction, 1000);  
    } 
} 

Xem thêm this fiddle

Tại thời điểm alert(count); bạn có thể thực hiện cuộc gọi đến máy chủ. Lưu ý rằng bộ đếm hoạt động ngược lại (đếm ngược). Tôi đã cập nhật một số số nhận xét nơi bạn làm việc của mình.

+0

Đó là hoạt động tuyệt vời. Cảm ơn rất nhiều. – glasspill

+0

Chào mừng. Nếu yêu cầu của bạn đến máy chủ không phải là thời gian quan trọng, bạn thậm chí còn tốt hơn sử dụng một công trình xây dựng, nơi một bộ đếm thời gian mới chỉ được bắt đầu sau khi cuộc gọi máy chủ trước đó đã kết thúc. Sau đó, chỉ có một cuộc gọi máy chủ sẽ hoạt động ngay cả khi cuộc gọi mất hơn 1 giây (giá trị bộ đếm thời gian setTimeout) –

+0

** WARNIG **: Giải pháp của bạn có thể dẫn đến 'RangeError: Kích thước ngăn xếp cuộc gọi tối đa đã vượt quá'. Vui lòng xem [giải pháp này] (http://stackoverflow.com/a/30575612/1480391) sử dụng 'setImmediate'. BTW OP đang sử dụng Node.js .. (không có 'cảnh báo' trong Node.js). –

1

Bạn đang gọi điện thoại makeRequest() trong cuộc gọi setTimeout của bạn - bạn nên đi qua các chức năng để setTimeout, không gọi nó, vì vậy cái gì đó như

setTimeout(makeRequest, 1000); 

mà không có()

2

Ngay bây giờ bạn đang lên lịch cho tất cả các yêu cầu của mình xảy ra cùng một lúc, chỉ một giây sau khi tập lệnh chạy. Bạn sẽ cần thực hiện một số việc như sau:

var numRequests = 2000, 
    cur = 1; 

function scheduleRequest() { 
    if (cur > numRequests) return; 

    makeRequest({ 
     host: 'www.host.com', 
     path: '/path/' + cur 
    }, cur); 

    cur++; 
    setTimeout(scheduleRequest, 1000) 
} 

Lưu ý rằng mỗi yêu cầu tiếp theo chỉ được lên lịch sau khi yêu cầu hiện tại hoàn tất.

+0

đó là những gì tôi nghĩ cũng như – glasspill

+0

@ jmar777 Tôi nhận ra rằng đây là một bài đăng cũ, tuy nhiên tôi có một vấn đề tương tự. Bạn có nhớ trả lời tại sao hàm 'scheduleRequest' không chuyển' cur' hoặc 'numRequests'? –

10

setTimeoutkhông chặn, không đồng bộ. Bạn cung cấp cho nó một cuộc gọi lại và khi sự chậm trễ kết thúc, gọi lại của bạn được gọi.

Dưới đây là một số hiện thực:

Sử dụng đệ quy

Bạn có thể sử dụng một recursive call trong setTimeout gọi lại.

function waitAndDo(times) { 
    if(times < 1) { 
    return; 
    } 

    setTimeout(function() { 

    // Do something here 
    console.log('Doing a request'); 

    waitAndDo(times-1); 
    }, 1000); 
} 

Dưới đây là làm thế nào để sử dụng chức năng của bạn:

waitAndDo(2000); // Do it 2000 times 

Về lỗi stack overflow: setTimeout rõ ràng các cuộc gọi stack (xem this question) do đó bạn không phải lo lắng về stack overflow trên setTimeout cuộc gọi đệ quy.

Sử dụng máy phát điện (io.js, ES6)

Nếu bạn đang sử dụng io.js ("tiếp theo" Node.js sử dụng ES6), bạn có thể giải quyết vấn đề của bạn mà không đệ quy với một giải pháp thanh lịch:

function* waitAndDo(times) { 
    for(var i=0; i<times; i++) { 

    // Sleep 
    yield function(callback) { 
     setTimeout(callback, 1000); 
    }  

    // Do something here 
    console.log('Doing a request'); 
    } 
} 

Dưới đây là làm thế nào để sử dụng chức năng của bạn (với co):

var co = require('co'); 

co(function*() { 
    yield waitAndDo(10); 
}); 

BTW: Đây thực sự là sử dụng một loop;)

Generator functions documentation.

0

Tôi có thể bị trễ tại bữa tiệc nhưng đây là giải pháp khác (dễ đọc hơn) mà không cần phải bỏ qua vòng lặp for.

gì mã của bạn đang tạo ra 2000 (thực sự 1999) setTimeout đối tượng sẽ gọi makeRequest chức năng sau 1 giây từ nay. Hãy xem, không ai trong số họ biết về sự tồn tại của các khác setTimeout s.

Nếu bạn muốn chúng cách nhau 1 giây, bạn có trách nhiệm tạo chúng như vậy.

Điều này có thể đạt được bằng cách sử dụng của bạn truy cập (trong trường hợp này i) và thời gian chờ chậm trễ.

for (var i = 1; i<=2000 && ok; i++) { 
    var options = { 
     host:'www.host.com', 
     path:'/path/'+i 
    }; 

    setTimeout(makeRequest(options, i), i * 1000); //Note i * 1000 
}; 

Đối tượng timeout đầu tiên sẽ được thiết lập cho 1 giây từ bây giờ và điều thứ hai sẽ được thiết lập cho 2 giây từ bây giờ và vân vân; Ý nghĩa 1 giây cách xa nhau.

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