2012-05-06 30 views
15

Tôi muốn lưu một số ~ 35000 đối tượng trong đối tượng IndexedDB của tôi. Tôi đang sử dụng mã dưới đây để chèn.Chèn số lượng lớn vào khối đối tượng của IndexedDB UI

AddListings = function (x2j_list_new, callback) { 
    var transaction = db.transaction(["listings"], IDBTransaction.READ_WRITE); 
    var count = 0; 
    transaction.oncomplete = function (event) { 
     if (callback) { 
      console.log('x2jShowListing Added ' + count + '/' + x2j_list_new.length); 
       callback([count, x2j_list_new.length]); 
      } 
    }; 
    transaction.onerror = function (e) { 
     console.log("myError: ", e); 
     if (callback) { 
      callback(false); 
     } 
    }; 
    var store = transaction.objectStore("listings"); 

    $.each(x2j_list_new, function (index0, item0) { 
     var request = store.put(item0); 
     request.onsuccess = function (event) { 
      count++; 
      // event.target.result 
      }; 
     }); 
    });   
}; 

Mã trên hoạt động tốt, nhưng lặp lại và chèn hơn 35000 đối tượng khiến giao diện người dùng không phản hồi trong ~ 200 giây. Tôi nghĩ có lẽ tôi có thể sử dụng WebWorkers, nhưng IndexedDB không có sẵn bên trong WebWorkers. Tôi cố gắng tìm cách chèn số lượng lớn, không thể tìm thấy. Bất kỳ ý tưởng nào về cách chèn số lượng lớn các đối tượng mà không chặn giao diện người dùng?

+1

Để bây giờ tôi đang tách mảng trong [khối] (http://stackoverflow.com/questions/ 8495687/split-array-into-chunks) 500 và sử dụng [setInterval] (http://www.kryogenix.org/days/2009/07/03/not-blocking-the-ui-in-tight-javascript- vòng lặp) thay vì cho vòng lặp. Bây giờ giao diện người dùng đáp ứng tốt hơn so với trước đây. – surya

Trả lời

28

Bạn đang đi đúng hướng, nhưng bạn đang yêu cầu trình duyệt lưu trữ 35.000 đối tượng trước khi nó có cơ hội hoàn tất lưu trữ. Đây là mã mà không đồng bộ chờ đợi một yêu cầu để kết thúc trước khi bắt đầu tiếp theo (nhưng sử dụng cùng một giao dịch):

openRequest = window.indexedDB.open("MyDatabase", 1); 
    openRequest.onerror = function(event) { 
     console.error(event); 
    }; 
    openRequest.onsuccess = function (event) { 
     var db = openRequest.result; 
     db.onerror = function(event) { 
      // Generic error handler for all errors targeted at this database's requests 
      console.error(event.target); 
      window.alert("Database error: " + event.target.wePutrrorMessage || event.target.error.name || event.target.error || event.target.errorCode); 
     }; 
     var transaction = db.transaction('item', "readwrite"); 
     var itemStore = transaction.objectStore("item"); 
     putNext(); 

     function putNext() { 
      if (i<items.length) { 
       itemStore.put(items[i]).onsuccess = putNext; 
       ++i; 
      } else { // complete 
       console.log('populate complete'); 
       callback(); 
      } 
     }   
    };  
+0

Đề xuất thú vị. Tò mò- Bất cứ ai chạy bất kỳ điểm chuẩn về hiệu suất đạt được điều này đạt được? –

+0

Để chắc chắn rằng tất cả các mục là ** thực sự ** trong cửa hàng - đăng ký sự kiện 'transaction.oncomplete', smth như:' transaction.oncomplete = callback' – Kiril

+0

Tôi không thể xem cách xác định kết thúc giao dịch , người ta nhận được một cửa hàng từ giao dịch sau đó thêm một hoặc nhiều hồ sơ ... Làm cách nào để giao dịch kết thúc sau khi tôi thêm tất cả? Giao dịch có kết thúc sau khi trả về cuộc gọi lại không? Đó là sau khi tất cả các mục được thêm vào trong cuộc gọi đệ quy này? Tôi cho là vậy – lisak

0

Bạn đang làm mọi thứ bạn đúng bằng cách sử dụng gọi lại.

API webworker chưa được thực hiện bởi bất kỳ trình duyệt chính nào. Điều thú vị là, nó được mong đợi là đồng bộ. API thông thường không đồng bộ với lý do chính xác mà bạn mô tả - nó không được phép chặn chuỗi giao diện người dùng.

Sử dụng gọi lại là cách tránh khóa bị khóa, nhưng tại 35k đối tượng bạn thấy rõ mô hình này bị hỏng. Thật không may, hiệu suất IDB vẫn chưa ngang bằng với WebSQL so với các tiêu chuẩn tôi đã thấy.

Với LevelDB của Chrome, có một số phụ trợ thử nghiệm mới (FF là SQLite) nhưng tôi nghĩ kinh nghiệm của bạn chứng minh rằng có một số chỗ để cải thiện.

0

Đoán ngẫu nhiên từ phía tôi, nhưng nếu WebSQL có sẵn từ cái được gọi là "trang nền" và giả sử băng thông nhắn tin giữa mặt trước và trang sau không khóa giao diện người dùng theo cùng cách, có thể có thể sử dụng một trang nền có thông điệp trang nội bộ không?

+0

Tôi có cảm giác rằng vòng lặp for đang gây ra giao diện người dùng khối. Tôi muốn có một cách để ping trình duyệt trong khoảng thời gian thường xuyên vì vậy nó không nghĩ rằng nó bị mắc kẹt – surya

+0

Trong lập trình GUI truyền thống, bạn có thể phát hiện khi trình duyệt là "nhàn rỗi" và thực hiện một bước trong vòng lặp lớn của bạn. Thật không may, phát hiện trạng thái nhàn rỗi không phải là dễ dàng trong javascript, nhưng có hacks để mô phỏng nó. Ví dụ: http://stackoverflow.com/questions/667555/detecting-idle-time-in-javascript-elegantly. –

0

Tôi đang chia mảng thành 500 và sử dụng setTimeout thay vì cho vòng lặp. Bây giờ giao diện người dùng phản hồi tốt hơn một chút so với trước đây

+0

Tôi không khuyên bạn nên truy cập IndexedDB từ nhiều tác vụ vòng lặp sự kiện. Nó hoạt động khá kỳ lạ theo cách này – lisak

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