Thursday, February 23, 2012

LINQ to Indexed DB

Since I started experimenting with the Indexed DB API, I have been searching for a simple way to add, retrieve, change, … data. In the beginning I wrote a little framework that provided some methods to retrieve, add, … data without having to think how to setup a connection. For experimenting this was enough, but when I started to build some demo apps, I noticed a needed a more generic way to do my CRUD operations.

So I start searching the internet for frameworks around the Indexed DB API’s. One project I found very interesting. It was the one of nparashuram. He was started with a Linq 2 Indexed DB Framework. Everything was still very basic, but it was well structured. Also it was only compatible with Firefox and Chrome, but not with the IE prototype and IE 10. So I contacted nparashuram and we decided to keep working on it together.

The framework is based on promises. This way we can easily handle the async calls which the Indexed DB API uses. We also use it as return value of the query you make. This way you can easily decide whether you want to use the complete method or the on progress method when retrieving multiple records. Also I believe this will be a programming model which we will see more and more in the future. Certainly if we want responsive applications.

The framework takes away the complexity of opening a database, creating transactions, … the only thing you need to worry about is how to structure your database and how to query. It also provides a way of creating the database structure while querying. This way you don’t have to create object stores or define the structure. Just inserting data to an object store, the object store will be created if not present.

The code of the framework can be found on codeplex and works as an extension on the jQuery framework. If you have some feature request you can add them here. Or you can contact me if you have some questions about it.

Keep following my blog or codeplex for new features and samples on this framework.

Friday, February 17, 2012

Web worker: running js tasks in the background

Since JavaScript is more and more used for building applications, rather than providing extra features, you need to take care you don’t freeze the UI. This is one of the reasons why the W3C introduced the web worker API. This API provides a way to run JavaScript in a thread different form the UI thread. This way long running code such as sorting large array’s, won’t freeze the the UI or make your application unresponsive. Generally, workers are expected to be long-lived, have a high startup performance cost and a high per-instance memory cost.

workers

When we want to run code in a thread different from the UI thread, then we need to put this code in separate file. This file, will then be called by the worker to run in another thread. The only thing you need to do in the in the code that will run in another thread is calling postMessage method whenever you want to send data to the UI-thread.

Continuous worker

This code will start running when ever a worker with that file is instantiated and will continue running.

Example of a file (prime.js) to run in the background:

   1: var n = 1;
   2: prime: while(true){
   3:     n += 1;
   4:     for (var i = 2; i <= Math.sqrt(n); i += 1){
   5:         if (n % i == 0){
   6:             continue prime;
   7:         }
   8:     }
   9:     // Found prime
  10:     postMessage(n)
  11: }

This code will send a message to the UI thread every time a prime is found.



   1: // Starts a new worker
   2: var worker = new Worker('prime.js');
   3: worker.onmessage = function (event){
   4:     // event.data contains a prime
   5:     document.getElementById("result").textContent = event.data
   6: }

The code above is used to create a new worker. The worker will execute the code in the prime.js file in a thread separate from the UI. In our case, the code will start calculating which numbers are primes.


The onmessage event on the worker gets triggered every time the postMessage method is called inside the worker thread. This way we can display the prime on the screen.


dedicated Worker


This worker will only start executing when you call the postMessage method on the worker.


Example of a file (sort.js) to run in the background:



   1: onmessage = function (event) {
   2:     var data = event.data.data;
   3:     var propertyName = event.data.propertyName;
   4:     var sortedData = data.sort(JSONComparer(propertyName).sort);
   5:     postMessage(sortedData);
   6:     return;
   7: };
   8:  
   9: function JSONComparer(propertyName) {
  10:     return {
  11:         sort: function (valueX, valueY) {
  12:                 return ((valueX[propertyName] == valueY[propertyName]) 
  13:                         ? 0 : ((valueX[propertyName] > valueY[propertyName]) ? 1 : -1));
  14:         }
  15:     }
  16: }

The onmessage method will handle a postMessage send to the worker. This will start the work you want to execute. In this case the code will sort an array of JSON objects on a given property. When the array and the propertyName is provided as data in the postMessage method, The data will get sorted on the property with the given propertyName. When the sort is completed, the sorted array will be send to the UI.



   1: var worker = new Worker("sort.js");
   2: var data = [{ name: "test2" }, [{ name: "test4" }, [{ name: "test1" }, [{ name: "test3" }]
   3: worker.onmessage = function (event) { /* event.data contains the sorted Array */) };
   4: worker.postMessage({ data: data, propertyName: "name"});

With the postMessage method we can provide the data that is needed to sort an array. When the sorting is completed and the postMessage method in the background thread is called, the onmessage function will be triggered in the UI thread so we can process the sorted array.


More information about workers can be found here.

Saturday, February 4, 2012

Indexed DB: To provide a key or not to provide a key

I am currently busy writing a little framework around the Indexed DB API to make it easier to use Indexed DB. One of the things I was struggling with was when the key parameter must or mustn’t be provided. So I tested every possible combinations.

For this I created 4 object stores with different combinations:

  • Object store 1: KeyPath: “Id”, autoIncrement = true
  • Object store 2: KeyPath: undefined, autoIncrement = true
  • Object store 3: KeyPath: “Id”, autoIncrement = false
  • Object store 4: KeyPath: undefined, autoIncrement = false

Next, I tried adding four different combinations, and here are the results.

Add/Put parameters

Object store configuration

Value

Key

Object store 1

Object store 2

Object store 3

Object store 4

{ Name: "test" } undefined successful successful failed failed
{ Id: 1, Name: "test" } undefined successful successful successful failed
{ Name: "test" } 1 failed successful failed successful
{ Id: 1, Name: "test" } 1 failed successful failed successful

 

Conclusion

  1. When a KeyPath is defined, the key parameter must be undefined
  2. When no KeyPath is defined and there is no autoIncrement, a key must be provided
  3. When no KeyPath is defined and there is autoIncrement, a key can be provided
  4. When a KeyPath is defined and there is no autoIncrement, an attribute with the name of the KeyPath must be present.