2011-11-29 31 views
7
window.onload = -> 

    boxOrig1 = 10 
    boxOrig2 = 30 
    canvasW = 400 
    canvasH = 300 

    ctx = $("#canvas")[0].getContext('2d'); 

    draw = (origin,dimension) ->  
    ctx.clearRect(0, 0, canvasW, canvasH) 
    ctx.fillStyle = 'rgb(200,0,0)' 
    ctx.fillRect(origin + boxOrig1, boxOrig1, dimension, dimension) 
    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)' 
    ctx.fillRect(origin + boxOrig2, boxOrig2, dimension, dimension) 

    for m in [10..100] by 10 
    t = setTimeout (-> draw(m, 150)), 1000 
    t.clearTimeout 
#  draw(m,150) 
#  alert m 

Như một bài tập, mã trên có nghĩa là vẽ một thiết kế nhỏ trên canvas, tạm dừng một giây rồi vẽ lại 10 pixel sang phải.Làm cách nào để sử dụng setTimout trong Coffeescript trong vòng lặp

Tôi có thể thấy rằng các cơ chế hoạt động tốt khi tôi ngắt vòng lặp với cảnh báo (như trong hai dòng nhận xét cuối), nhưng tôi không nhận được hành vi mong đợi với hàm setTimeout. Thiết kế chỉ xuất hiện ở vị trí ngoài cùng bên phải sau khi hết thời gian chờ, bỏ qua các bước gia tăng ở giữa.

Tôi đã thử nhiều cách khác nhau để làm điều này từ các ví dụ khác, nhưng nó chỉ làm tan chảy bộ não của tôi. Bất kỳ đề xuất?

Trả lời

10

Geoff đã vạch ra một cách tiếp cận (sử dụng setInterval và cách xóa nó khỏi gọi lại), vì vậy tôi sẽ phác thảo khác: Sử dụng setTimeout từ callback . Một cái gì đó như

m = 10 
do drawCallback = -> 
    draw m, 150 
    m += 10 
    setTimeout drawCallback, 1000 unless m > 100 

Lưu ý rằng có một sự khác biệt thời gian tinh tế giữa hai cách tiếp cận mà bạn cần phải nhận thức: setInterval func, 1000 sẽ chạy chức năng một lần 1000ms; chuỗi setTimeout sẽ đặt độ trễ 1000ms giữa mỗi lần gọi hàm. Vì vậy, nếu draw mất 100 mili giây, thì chuỗi setTimeout sẽ tương đương với setInterval func, 1100. Nó có lẽ không quan trọng, nhưng nó đáng được nhận thức.

Phương thức thưởng: Bạn không để từ bỏ vòng lặp của mình; bạn chỉ có thể đặt tất cả các timeouts từ nó cùng một lúc:

for m in [10..100] by 10 
    do (m) -> 
    setTimeout (-> draw(m, 150)), 100 * m 

Các do (m) là cần thiết để việc đóng cửa truyền cho setTimeout thấy mỗi giá trị của m, không chỉ là giá trị cuối cùng của nó trong vòng lặp. Xem bài viết của tôi A CoffeeScript Intervention để biết thêm thông tin về điều này.

Cuối cùng: Tôi biết điều này dường như rất khó hiểu lúc đầu, nhưng thời gian trong JS thực sự rất đơn giản vì ngôn ngữ là đơn luồng. Điều đó có nghĩa là các sự kiện bạn lập lịch với setTimeout hoặc setInterval hoặc bất kỳ chức năng async nào khác sẽ không bao giờ xảy ra trong vòng một vòng lặp, ngay cả khi vòng lặp là vô hạn. Chúng chỉ xảy ra sau khi tất cả mã của bạn đã hoàn thành việc thực thi. Tôi nói về điều này chi tiết hơn một chút trong my book on CoffeeScript.

+0

Khái niệm quan trọng mà tôi đã bỏ lỡ là việc bỏ qua việc đóng cửa thông qua từ khóa "do". Như chúng ta Perlers muốn nói, TMTOWTDI. Cảm ơn tất cả! Bây giờ trở lại để thực hành :-) – user105090

+0

Giải thích nổi bật. –

+0

câu trả lời này có ích, đẹp nhất Trevor https://twitter.com/#!/karlseguin/status/165442250376085504 –

2

Điều này có thể được thể hiện bằng trực giác hơn là một setInterval:

window.onload = -> 

    boxOrig1 = 10 
    boxOrig2 = 30 
    canvasW = 400 
    canvasH = 300 

    ctx = document.getElementById("canvas").getContext('2d') 

    draw = (origin,dimension) -> 
    ctx.clearRect(0, 0, canvasW, canvasH) 
    ctx.fillStyle = 'rgb(200,0,0)' 
    ctx.fillRect(origin + boxOrig1, boxOrig1, dimension, dimension) 
    ctx.fillStyle = 'rgba(0, 0, 200, 0.5)' 
    ctx.fillRect(origin + boxOrig2, boxOrig2, dimension, dimension) 

    count = 10 
    timer = setInterval (-> 
    if count == 100 
     clearInterval(timer) 
    draw(count, 150); count+=10 
), 1000 
Các vấn đề liên quan