2009-07-21 49 views
37

Tôi có một tác vụ cpu chuyên sâu mà tôi cần để chạy trên máy khách. Lý tưởng nhất, tôi muốn có thể gọi hàm và kích hoạt các sự kiện tiến trình bằng cách sử dụng jquery để tôi có thể cập nhật giao diện người dùng.Thực hiện tác vụ nền trong Javascript

Tôi biết javascript không hỗ trợ luồng, nhưng tôi đã nhìn thấy một số bài viết đầy hứa hẹn đang cố gắng bắt chước luồng bằng cách sử dụng setTimeout.

Cách tiếp cận tốt nhất để sử dụng cho điều này là gì? Cảm ơn.

Trả lời

18

Tôi đã gặp sự cố tương tự để giải quyết gần đây nơi tôi cần giữ nguyên chuỗi giao diện người dùng của mình trong khi crunching một số dữ liệu để hiển thị.

Tôi đã viết một thư viện Background.js để xử lý một vài kịch bản: một hàng đợi nền tuần tự (dựa trên thư viện WorkerQueue), danh sách các công việc mà mỗi được gọi trên mỗi bộ đếm thời gian. làm việc thành những phần nhỏ hơn. Ví dụ và mã ở đây: https://github.com/kmalakoff/background

Tận hưởng!

4

Tùy thuộc vào yêu cầu của bạn là gì, bạn có thể thoát ra dễ dàng bằng cách sử dụng Gears. Gears hỗ trợ chủ đề, có thể làm những gì bạn muốn.

Như bạn đã đề cập, setTimeout là tùy chọn khác. Tùy thuộc vào loại nhiệm vụ của bạn, bạn có thể đưa ra từng vòng lặp của một vòng lặp đến một cuộc gọi setTimeout riêng biệt với một khoảng cách ở giữa hoặc bạn có thể cần phân tách các thuật toán chính thành các hàm riêng biệt. giống như cách bạn gọi cho mỗi lần lặp lại.

+0

+1, nhưng 'công nhân' bánh răng không chính xác những gì môi trường khác gọi là 'chủ đề'. – Javier

+0

Firefox 3.5 cũng có công nhân chuẩn hóa W3. Xem câu trả lời của tôi cho các liên kết. – Blixt

1

Đề xuất mạnh nhất của tôi là hiển thị loading.gif đơn giản trong quá trình hoạt động. Người dùng thường chấp nhận một số thời gian nếu họ đã được "nói" rằng nó có thể mất một thời gian.

Ajaxload - Ajax loading gif generator

35

Về cơ bản, những gì bạn muốn làm là chia hoạt động thành từng mảnh. Vì vậy, nói rằng bạn có 10 000 mục bạn muốn xử lý, lưu trữ chúng trong một danh sách và sau đó xử lý một số lượng nhỏ trong số họ với một sự chậm trễ nhỏ giữa mỗi cuộc gọi. Đây là cấu trúc đơn giản mà bạn có thể sử dụng:

function performTask(items, numToProcess, processItem) { 
    var pos = 0; 
    // This is run once for every numToProcess items. 
    function iteration() { 
     // Calculate last position. 
     var j = Math.min(pos + numToProcess, items.length); 
     // Start at current position and loop to last position. 
     for (var i = pos; i < j; i++) { 
      processItem(items, i); 
     } 
     // Increment current position. 
     pos += numToProcess; 
     // Only continue if there are more items to process. 
     if (pos < items.length) 
      setTimeout(iteration, 10); // Wait 10 ms to let the UI update. 
    } 
    iteration(); 
} 

performTask(
    // A set of items. 
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'], 
    // Process two items every iteration. 
    2, 
    // Function that will do stuff to the items. Called once for every item. Gets 
    // the array with items and the index of the current item (to prevent copying 
    // values around which is unnecessary.) 
    function (items, index) { 
     // Do stuff with items[index] 
     // This could also be inline in iteration for better performance. 
    }); 

Cũng lưu ý rằng Google Gears has support to do work on a separate thread. Firefox 3.5 cũng đã giới thiệu its own workers that do the same thing (mặc dù họ theo dõi the W3 standard, trong khi Google Gears sử dụng các phương pháp riêng của mình.)

+1

Cảm ơn. Điều này làm việc rất tốt cho tôi, nhưng tôi đã làm việc với một mảng dữ liệu để nó có thể không phải là giải pháp tốt nhất cho mọi người. – Rob

+0

Sẽ không hoạt động đối với điều khiển hiện tại như chế độ xem dạng cây không hỗ trợ chia nhỏ tác vụ như cập nhật cây, liên quan đến việc lặp qua từng nút. – Triynko

1

Đây là một ví dụ rất cơ bản về cách tạo chủ đề bằng JavaScript. Lưu ý rằng bạn có thể làm gián đoạn các chức năng chủ đề của mình (chỉ dẫn yeld). Nếu bạn muốn, bạn có thể sử dụng một setTimeout thay vì của tôi trong khi lặp lại để chạy trình lên lịch định kỳ. Cũng lưu ý rằng ví dụ này chỉ làm việc với phiên bản JavaScript 1.7+ (firefox 3+) bạn có thể thử nó ở đây: http://jslibs.googlecode.com/svn/trunk/jseval.html

//// thread definition 
function Thread(name) { 

    for (var i = 0; i < 5; i++) { 

     Print(i+' ('+name+')'); 
     yield; 
    } 
} 

//// thread management 
var threads = []; 

// thread creation 
threads.push(new Thread('foo')); 
threads.push(new Thread('bar')); 

// scheduler 
while (threads.length) { 

    var thread = threads.shift(); 
    try { 
     thread.next(); 
     threads.push(thread); 
    } catch(ex if ex instanceof StopIteration) { } 
} 

Đầu ra là:

0 (foo) 0 (bar) 1 (foo) 1 (bar) 2 (foo) 2 (bar) 3 (foo) 3 (bar) 4 (foo) 4 (bar) 
+0

Đó là thực sự gọn gàng mặc dù không khả thi trừ khi người dùng có thể bị buộc phải sử dụng Firefox 3+. '=)' Tôi thực sự thích bộ đánh giá JavaScript của bạn, tôi sẽ đánh dấu trang đó! '=)' – Blixt

+0

Xin chào, cảm ơn! Có lẽ bạn có thể xem dự án jslibs: http://code.google.com/p/jslibs –

8

Nếu bạn có thể thực thi các trình duyệt được sử dụng, hoặc bạn đã biết đó là phiên bản Firefox mới, bạn có thể sử dụng WebWorkers mới từ Mozilla. Nó cho phép bạn tạo ra các luồng mới.

2

Câu trả lời hay Kevin! Tôi đã viết một cái gì đó tương tự như một vài năm trở lại, mặc dù ít phức tạp.mã nguồn là ở đây nếu có ai muốn nó:

http://www.leapbeyond.com/ric/jsUtils/TaskQueue.js

Bất cứ điều gì với một phương pháp run() có thể được xếp hàng đợi như một nhiệm vụ. Các tác vụ có thể tự xếp hàng lại để thực hiện công việc theo khối. Bạn có thể ưu tiên các tác vụ, thêm/xóa chúng theo ý muốn, tạm dừng/tiếp tục toàn bộ hàng đợi, vv Hoạt động tốt với các hoạt động không đồng bộ - việc sử dụng ban đầu của tôi là quản lý một số XMLHttpRequests đồng thời.

sử dụng cơ bản là khá đơn giản:

var taskQueue = new TaskQueue(); 
taskQueue.schedule("alert('hello there')"); 

Các ý kiến ​​tiêu đề trong file .js cung cấp ví dụ nâng cao hơn.

0

Dường như vấn đề này đã được giải quyết trong chính nút.
đòi hỏi child_process được bao gồm trong nodejs 0.10.4

2

Đây là giải pháp của tôi cho vấn đề, trong trường hợp ai đó muốn đơn giản mảnh sao chép pasteable mã:

var iterate = function (from, to, action, complete) { 
     var i = from; 
     var impl = function() { 
      action(i); 
      i++; 
      if (i < to) setTimeout(impl, 1); 
      else complete(); 
     }; 
     impl(); 
    }; 
Các vấn đề liên quan