2008-10-18 42 views
17

Tôi đang làm việc với một API JavaScript, nơi hầu hết các chức năng đều không đồng bộ. API là WebKit JavaScript Database API là một ràng buộc với một tập con chức năng để thao tác cơ sở dữ liệu SQLite3. Tôi hiểu quyết định thiết kế để làm cho mọi thứ không đồng bộ như không chặn và cung cấp giao diện người dùng đáp ứng. Trong tình huống của tôi, tôi biết rằng việc sử dụng các cuộc gọi API async của tôi sẽ thực thi nhanh. Vì đây là trường hợp tôi muốn cung cấp cho các nhà phát triển của tôi một trình bao bọc API sạch hơn và dễ sử dụng hơn để buộc các cuộc gọi đồng bộ.Mẫu để gói một hàm JavaScript không đồng bộ để làm cho nó đồng bộ

Dưới đây là cuộc gọi async

db.executeSql(sqlStatement, function(result) { 
    // do something with result 
}); 

Và đây là những gì tôi muốn để có thể làm

var result = dbWrapper.executeSql(sqlStatement); 
// do something with result 

Có một thiết kế mô hình/cách để làm điều này? Một ví dụ được viết hoặc liên kết với mã được ưu tiên. Nền tảng/broswer đích là Mobile Safari trên iPhone.

Cảm ơn bạn

+0

Sẽ rất thú vị nếu bạn nhận được câu trả lời, vì tôi nghi ngờ điều đó là không thể (ít nhất là không có hỗ trợ luồng, mà Safari sẽ không đưa cho bạn). –

Trả lời

1

nếu bạn đang sử dụng jQuery Ajax: $ .ajax()

bạn có thể thiết lập các thuộc tính của asynch false, và sau đó bạn sẽ có một yêu cầu đồng bộ ajax đến máy chủ .

+2

Tôi đã xem xét cách thức jQuery thực hiện hàm $ .ajax() của nó với việc sử dụng một boolean không đồng bộ, nhưng hóa ra nó chỉ truyền tham số async thông qua hàm XMLHttpRequest.open được thực hiện trong mã "nguyên gốc" (không phải js) và do đó có thể buộc hành vi đồng bộ. – pfeilbr

1

Chúng tôi đang sử dụng GWT RPC cũng có API không đồng bộ. Các giải pháp mà chúng tôi đang sử dụng để thực hiện một số cuộc gọi async trong sê-ri là cuộc gọi chaining:

callA(function(resultA) { 
    callB(resultA, function(resultB) { 
     callC(); //etc. 
    }); 
}); 

cách tiếp cận lồng nhau này đạt được những gì bạn muốn nhưng nó là verbose và khó đọc cho người mới. Một trong những phương pháp mà chúng tôi đã điều tra được thêm các cuộc gọi mà chúng ta cần phải thực hiện để một chồng và thực hiện chúng theo thứ tự:

callStack = [ 
    callA(), 
    callB(), 
    callC() 
]; 

callStack.execute(); 

Sau đó callstack sẽ quản lý:

  1. Gọi các cuộc gọi trong sê-ri (ví dụ: hệ thống dây điện trong ví dụ đầu tiên)
  2. Chuyển kết quả từ một cuộc gọi đến tiếp theo.

Tuy nhiên, vì Java không có tham chiếu hàm, mỗi cuộc gọi trên ngăn xếp cuộc gọi sẽ yêu cầu một lớp ẩn danh nên chúng tôi đã dừng một giải pháp như vậy. Tuy nhiên, bạn có thể có nhiều thành công hơn trong javascript.

Chúc may mắn!

10

Xin lỗi, JavaScript không cung cấp ngôn ngữ gốc (ví dụ: chủ đề hoặc coroutines) để làm cho những thứ không đồng bộ hoạt động đồng bộ hoặc ngược lại.

Thông thường, bạn chỉ nhận được một chuỗi thực thi, do đó bạn không thể nhận được cuộc gọi lại từ bộ đếm giờ hoặc XMLHttpRequest readystatechange cho đến khi chồng các cuộc gọi dẫn đến việc tạo yêu cầu đã hoàn toàn làm sáng tỏ.

Vì vậy, trong ngắn hạn, bạn không thể thực sự làm điều đó; cách tiếp cận với các đóng cửa lồng nhau trên trang WebKit mà bạn đã liên kết là cách duy nhất tôi biết để làm cho mã có thể đọc được trong tình huống này.

*: ngoại trừ trong một số tình huống khó hiểu đó sẽ không giúp bạn và thường được coi là lỗi

+1

Điều đó có ý nghĩa hoàn hảo. Cảm ơn lời giải thích rõ ràng. – pfeilbr

+1

Cập nhật năm 2014, JavaScript hiện chứa ngôn ngữ nguyên thủy (coroutines) để giải quyết vấn đề này, mặc dù hỗ trợ hiện bị giới hạn ở NodeJS, Chrome dưới cờ và Firefox. https://github.com/petkaantonov/bluebird/blob/master/API.md#promisecoroutinegeneratorfunction-generatorfunction---function –

4

Bạn có thể thử một cái gì đó như:

function synch() 
{ 
    var done = false; 
    var returnVal = undefined; 

    // asynch takes a callback method 
    // that is called when done 
    asynch(function(data) { 
     returnVal = data; 
     done = true; 
    }); 

    while (done == false) {}; 
    return returnVal; 
} 

Nhưng điều đó có thể đóng băng trình duyệt của bạn trong suốt thời gian của phương pháp asynch ...

Hoặc xem qua JavaScript tường thuật: JavaScript tường thuật là một phần mở rộng nhỏ cho ngôn ngữ JavaScript cho phép chặn khả năng gọi lại sự kiện không đồng bộ. Điều này làm cho mã không đồng bộ có thể đọc được và dễ hiểu.

http://neilmix.com/narrativejs/doc/index.html

Mike

+3

JavaScript không có chủ đề, thao tác này sẽ không bao giờ hoạt động. Khi vòng lặp 'while' được bắt đầu, nó sẽ không bao giờ kết thúc. – naomik

+0

bạn đúng, đọc bản thân mình sau một vài năm làm cho tôi cảm thấy ngớ ngẩn;) –

+0

Đừng đánh bại chính mình lên trên nó. Tôi thực sự nghĩ rằng điều này sẽ làm việc quá trước khi tôi đã thử nó cho bản thân mình ^.^ – naomik

0

này không thực sự thực hiện hoạt động đồng bộ của truy vấn db, nhưng đây là giải pháp của tôi để quản lý dễ dàng. Về cơ bản, sử dụng hàm gọi làm hàm gọi lại và kiểm tra đối số kết quả. Nếu hàm nhận được kết quả, nó sẽ phân tích cú pháp chúng, nếu không, nó sẽ gửi chính nó như là một cuộc gọi lại đến phương thức truy vấn.

render: function(queryResults){ 
    if (typeof queryResults != 'undefined'){ 
    console.log('Query completed!'); 
    //do what you will with the results (check for query errors here) 

    } else { 
    console.log('Beginning query...'); 
    this.db.read(this.render); //db.read is my wrapper method for the sql db, and I'm sending this render method as the callback. 
    } 
} 
+0

Bạn cũng có thể có một chức năng gọi lại riêng biệt. Làm cho chức năng người gọi cũng là chức năng gọi lại chỉ gây nhầm lẫn cho tình huống – Dean

8

StratifiedJS cho phép bạn làm chính xác điều đó.

Thậm chí còn có một bài viết về làm thế nào để áp dụng nó vào lưu trữ trình duyệt: http://onilabs.com/blog/stratifying-asynchronous-storage

Và đây là thư viện phân tầng JavaScript nó sử dụng https://gist.github.com/613526

Ví dụ đi như thế:

var db = require("webdatabase").openDatabase("CandyDB", ...); 
try { 
    var kids = db.executeSql("SELECT * FROM kids").rows; 
    db.executeSql("INSERT INTO kids (name) VALUES (:name);", [kids[0]]); 
    alert("done"); 
} catch(e) { 
    alert("something went wrong"); 
} 

lẽ một chút muộn, nhưng công nghệ không tồn tại trở lại sau đó;)

+0

Liên kết đến GitHub Nguồn: https://github.com/onilabs/stratifiedjs –

0

Tôi không chắc chắn nếu đây là đúng nơi nhưng tôi cam ở đây tìm kiếm câu trả lời để thực hiện cuộc gọi đồng bộ trong Firefox. giải pháp sẽ là loại bỏ gọi lại onreadystatechange và thực hiện cuộc gọi trực tiếp. Đây là những gì tôi đã tìm thấy và giải pháp của tôi synchronous call back with rest service

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