2016-01-17 28 views
5

Tôi đã tạo đối tượng này chứa một mảng, phục vụ như một hàng đợi công việc.Hàng đợi công việc JavaScript

Nó loại công trình như thế này:

var work1 = new Work(); 
var work2 = new Work(); 
var queue = Workqueue.instance(); 

queue.add(work1) // Bluebird promise. 
.then(function addWork2() { 
    return queue.add(work2); 
}) 
.then(function toCommit() { 
    return queue.commit(); 
}) 
.then(function done(results) { 
    // obtain results here. 
}) 
.catch(function(err){}); 

Nó hoạt động trong trường hợp đó và tôi có thể cam kết nhiều hơn một nhiệm vụ trước khi tôi gọi là cam kết.

Tuy nhiên, nếu đó là như thế này:

var work1 = new Work(); 
var work2 = new Work(); 
var queue = Workqueue.instance(); 

queue.add(work1) 
.then(function toCommit1() { 
    return queue.commit(); 
}) 
.then(function done1(result1) { 
    // obtain result1 here. 
}) 
.catch(function(err){}); 

queue.add(work2) 
.then(function toCommit2() { 
    return queue.commit(); 
}) 
.then(function done2(result2) { 
    // obtain result2 here. 
}) 
.catch(function(err){}); 

Something có thể đi sai, bởi vì nếu là người đầu tiên cam kết được gọi sau khi thứ hai cam kết (hai tác phẩm/công việc đã được gia tăng), người đầu tiên cam kết xử lý hy vọng một kết quả nhưng tất cả đều đi đến trình xử lý cam kết thứ hai.

Nhiệm vụ liên quan đến cơ sở dữ liệu Web SQL đã đọc và cũng có thể liên quan đến truy cập mạng. Vì vậy, về cơ bản nó là một thủ tục phức tạp nên vấn đề mô tả ở trên có thể xuất hiện. Nếu chỉ có tôi mới có thể triển khai addWorkAndCommit() bao gồm addcommit cùng nhau, nhưng vẫn không đảm bảo vì addWorkAndCommit() không thể "nguyên tử" theo nghĩa bởi vì chúng liên quan đến các cuộc gọi không đồng bộ. Vì vậy, ngay cả hai cuộc gọi đến addWorkAndCommit() có thể không thành công. (Tôi không biết làm thế nào để mô tả nó khác hơn là "nguyên tử", kể từ khi JavaScript là đơn luồng, nhưng vấn đề này cây trồng lên).

Tôi có thể làm gì?

+0

Sử dụng mẫu bỏ qua: http://stackoverflow.com/questions/28915677/what-is-the-promise-disposer-pattern –

+0

@BenjaminGruenbaum Tôi không biết cách triển khai trong vấn đề này. – huggie

Trả lời

3

Vấn đề là có commit() nhưng không có khái niệm về giao dịch, do đó bạn không thể rõ ràng có hai giao dịch riêng biệt chạy song song. Theo hiểu biết của tôi, Javascript Workqueue là một proxy cho hàng đợi từ xa và các cuộc gọi đến add()commit() ánh xạ trực tiếp tới một số loại cuộc gọi thủ tục từ xa có giao diện tương tự mà không có giao dịch. Tôi cũng hiểu rằng bạn sẽ không quan tâm nếu add() thứ hai thực sự xảy ra sau commit() đầu tiên, bạn chỉ muốn viết hai câu lệnh addWorkAndCommit() tiếp theo đơn giản mà không đồng bộ hóa các cuộc gọi cơ bản trong mã máy khách.

Những gì bạn có thể làm là viết một gói bao quanh địa phương Workqueue (hoặc thay đổi trực tiếp nếu đó là mã của bạn), để mỗi cập nhật hàng đợi tạo giao dịch mới và commit() luôn đề cập đến một giao dịch như vậy. Trình bao bọc sau đó trì hoãn các bản cập nhật mới cho đến khi tất cả các giao dịch trước đó được cam kết (hoặc cuộn lại).

+0

Oh wow! Thật là một giải pháp đơn giản. Một thời điểm eureka cho những gì một giao dịch thực sự có nghĩa là. Cảm ơn tôi đã đập đầu của tôi trên này cố gắng để thực hiện synchronicity. – huggie

+0

Việc thực hiện đó là trong đầu của tôi ngay bây giờ là giao dịch nên là một đối tượng cần được tiếp xúc với khách hàng của hàng đợi. Với khách hàng một cách rõ ràng biết giao dịch mà công việc được thêm vào. Đúng không? – huggie

+0

Nó phụ thuộc. Nếu bạn muốn các phương thức add() và commit() riêng biệt trong giao diện của bạn, thì có. Nếu bạn có phương thức addWorkAndCommit() làm phương thức thì người gọi không cần biết gì về giao dịch. – lex82

1

Thông qua đề nghị Benjamin Gruenbaum để sử dụng một mô hình tiêu hủy, đây là một, viết như một phương pháp adapter cho Workqueue.instance():

Workqueue.transaction = function (work) { // `work` is a function 
    var queue = this.instance(); 
    return Promise.resolve(work(queue)) // `Promise.resolve()` avoids an error if `work()` doesn't return a promise. 
    .then(function() { 
     return queue.commit(); 
    }); 
} 

Bây giờ bạn có thể viết:

// if the order mattters, 
// then add promises sequentially. 
Workqueue.transaction(function(queue) { 
    var work1 = new Work(); 
    var work2 = new Work(); 
    return queue.add(work1) 
    .then(function() { 
     return queue.add(work2); 
    }); 
}); 
// if the order doesn't mattter, 
// add promises in parallel. 
Workqueue.transaction(function(queue) { 
    var work1 = new Work(); 
    var work2 = new Work(); 
    var promise1 = queue.add(work1); 
    var promise2 = queue.add(work2); 
    return Promise.all(promise1, promise2); 
}); 
// you can even pass `queue` around 
Workqueue.transaction(function(queue) { 
    var work1 = new Work(); 
    var promise1 = queue.add(work1); 
    var promise2 = myCleverObject.doLotsOfAsyncStuff(queue); 
    return Promise.all(promise1, promise2); 
}); 

Trong thực tế, một xử lý lỗi phải được bao gồm như thế này - Workqueue.transaction(function() {...}).catch(errorHandler);

Wh bất cứ lúc nào bạn viết, tất cả những gì bạn cần làm là đảm bảo rằng hàm gọi lại trả về một lời hứa là tổng hợp của tất cả các đồng bộ thành phần (lời hứa thành phần). Khi lời hứa tổng hợp giải quyết, người hủy bỏ sẽ đảm bảo rằng giao dịch được thực hiện.

Giống như tất cả các thiết bị phân loại, thiết bị này không làm bất cứ điều gì bạn không thể làm mà không có nó.Tuy nhiên nó:

  • đóng vai trò như một lời nhắc nhở về những gì bạn đang làm bằng cách cung cấp một tên .transaction() phương pháp,
  • thực thi khái niệm về một giao dịch duy nhất bằng cách kìm hãm một Workqueue.instance()-một cam kết.

Nếu vì bất kỳ lý do nào bạn cần phải thực hiện hai hoặc nhiều lần commit trên cùng một hàng đợi (tại sao?), Thì bạn luôn có thể quay lại gọi trực tiếp Workqueue.instance().

+0

Thật là một giải pháp tuyệt vời! Cảm ơn bạn rất nhiều. – huggie

+0

Khái niệm giao dịch có nên được mở rộng đến mọi lớp giao diện không? Nó có vẻ như khi tôi có một giao dịch, lỗi vẫn đạo cụ lên. Kết quả công việc vẫn có thể không xác định. – huggie

+0

Mmmm, không quá chắc chắn. Liệu các giải pháp khác thể hiện cùng một vấn đề? –

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