SlideShare ist ein Scribd-Unternehmen logo
1 von 26
Downloaden Sie, um offline zu lesen
R a y B e l l i s
@ r a y b e l l i s
j Q u e r y U K – 2 0 1 3 / 0 4 / 1 9
1
Persistent Memoization using
HTML5 indexedDB and Promises
What is Memoization?
2
“Automatic caching of a pure function’s return value,
so that a subsequent call with the same parameter(s)
obtains the return value from a cache instead of
recalculating it.”
Avoiding:
  Expensive calculations
  Repeated AJAX calls…
Memoization Example Implementation
3
$.memoize = function(factory, ctx) {	
var cache = {};	
return function(key) {	
if (!(key in cache)) {	
cache[key] = factory.call(ctx, key);	
}	
return cache[key];	
};	
};
Usage #1 – Expensive Calculations
4
// recursive Fibonacci – O(~1.6^n) !!	
var fib = function(n) {	
return (n < 2) ? n : fib(n – 1) + fib(n – 2);	
}	
// wrap it	
fib = $.memoize(fib);	
The results of recursive calls are delivered from the cache
instead of being recalculated.
The algorithm improves from O(~1.6^n) to O(n) for first
run, and O(1) for previously calculated values of “n”.
Usage #2 – Repeated AJAX Calls
5
// AJAX function – returns a “Promise”	
// expensive to call – may even cost real money!	
function getGeo(ip) {	
return $.getJSON(url, {ip: ip});	
}	
// create a wrapped version	
var memoGeo = $.memoize(getGeo);	
memoGeo(“192.168.1.1”).done(function(data) {	
...	
});	
Repeated calls to the wrapped function for the same
input return the same promise, and thus the same result.
Usage #2 – Repeated AJAX Calls
6
// AJAX function – returns a “Promise”	
// expensive to call – may even cost real money!	
function getGeo(ip) {	
return $.getJSON(url, {ip: ip});	
}	
// create a wrapped version	
var memoGeo = $.memoize(getGeo);	
memoGeo(“192.168.1.1”).done(function(data) {	
...	
});	
Repeated calls to the wrapped function for the same
input return the same promise, and thus the same result.
How could I cache results between sessions?
HTML5 “indexedDB” to the Rescue
7
  Key/Value Store
  Values may be Objects
  localStorage only allows Strings
  Databases are origin specific (CORS)
  Multiple tables (“object stores”) per Database
  Asynchronous API
  Sync API exists but may be deprecated by W3C
  Schema changes require “Database Versioning”
Database Versioning
8
$.indexedDB = function(dbname, store) {	
var version; // initially undefined	
(function retry() {	
var request;	
if (typeof version === "undefined") {	
request = indexedDB.open(dbname); // open latest version	
} else {	
request = indexedDB.open(dbname, version) // or open specific version number	
}	
request.onsuccess = function(ev) {	
var db = ev.target.result;	
if (!db.objectStoreNames.contains(store)) { // if the store is missing	
version = db.version + 1; // increment version number	
db.close(); // close the DB	
retry(); // and open it again – NB: recursion!	
} else {	
// use the database here	
...	
}	
};	
request.onupgradeneeded = function(ev) {	
var db = ev.target.result;	
db.createObjectStore(store); // create new table	
};	
})(); // invoke immediately	
}
Callbacks…
9
$.indexedDB = function(dbname, store, callback) {	
var version; // initially undefined	
(function retry() {	
var request;	
if (typeof version === "undefined") {	
request = indexedDB.open(dbname); // open latest version	
} else {	
request = indexedDB.open(dbname, version) // or open specific version number	
}	
request.onsuccess = function(ev) {	
var db = ev.target.result;	
if (!db.objectStoreNames.contains(store)) { // if the store is missing	
version = db.version + 1; // increment version number	
db.close(); // close the DB	
retry(); // and open it again – NB: recursion!	
} else {	
// use the database here	
callback(db);	
}	
};	
request.onupgradeneeded = function(ev) {	
var db = ev.target.result;	
db.createObjectStore(store); // create new table	
};	
})(); // invoke immediately	
}
… are so 2010!
10
  jQuery Promises
  Introduced in jQuery 1.5
  Incredibly useful for asynchronous event handling
  Rich API
  $.when()
  .done()
  .then()
  etc
Let’s ditch those callbacks!
11
$.indexedDB = function(dbname, store) {	
var def = $.Deferred(); // I promise to return ...	
var version;	
(function retry() {	
var request;	
if (typeof version === "undefined") {	
request = indexedDB.open(dbname);	
} else {	
request = indexedDB.open(dbname, version);	
}	
request.onsuccess = function(ev) {	
var db = ev.target.result;	
if (!db.objectStoreNames.contains(store)) {	
version = db.version + 1;	
db.close();	
retry();	
} else {	
// use the database here	
def.resolve(db); // Tell the caller she can use the DB now	
} 	
};	
request.onupgradeneeded = function(ev) {	
var db = ev.target.result;	
db.createObjectStore(store);	
};	
})();	
return def.promise(); // I really do promise...	
};
Usage
12
$.indexedDB("indexed", store).done(function(db) {	
// use "db" here	
...	
});
Getting Back to Memoization
13
  One Database – avoids naming collisions
  One object store per memoized function
  Use Promises for consistency with other jQuery
async operations
No, I didn’t figure all this out in advance!
Code Walkthrough
14
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
We need to return a function…
15
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
that returns a Promise…
16
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
and requires a DB connection…
17
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
that looks up the key…
18
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
and if found, resolves the Promise…
19
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
otherwise, calls the original function…
20
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
and $.when .done, stores it in the DB…
21
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
and asynchronously resolves the Promise
22
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
if it can…
23
$.memoizeForever = function(factory, store, keyPath, ctx) {	
var idb = $.indexedDB("indexed", store, keyPath);	
return function(key) {	
var def = $.Deferred();	
idb.done(function(db) {	
db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) {	
if (typeof ev.target.result === "undefined") {	
$.when(factory.call(ctx, key)).done(function(data) {	
db.transaction(store, "readwrite").objectStore(store)	
.add(data).onsuccess = function()	
{	
def.resolve(data);	
};	
}).fail(def.reject);	
} else {	
def.resolve(ev.target.result);	
}	
};	
});	
return def.promise();	
};	
};
Persistent Memoization Usage
24
// AJAX function – returns a “Promise”	
// expensive to call – may even cost real money!	
function getGeo(ip) {	
return $.getJSON(url, {ip: ip});	
}	
// create a wrapped version	
// Object store name is "geoip" and JSON path to key is "ip"	
var memoGeo = $.memoizeForever(getGeo, "geoip", "ip");	
memoGeo("192.168.1.1”).done(function(data) {	
...	
});	
Now, repeated calls to the function return previously
obtained results, even between browser sessions!
Download
25
Source available at:
https://gist.github.com/raybellis/5254306#file-jquery-memoize-js
Questions?
26

Weitere ähnliche Inhalte

Was ist angesagt?

Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with JasmineLeon van der Grient
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Kacper Gunia
 
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupKacper Gunia
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackGaryCoady
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
A Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsA Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsMark Baker
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needKacper Gunia
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to NodejsGabriele Lana
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersKacper Gunia
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConRafael Dohms
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web servicesMichelangelo van Dam
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptIngvar Stepanyan
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門Tsuyoshi Yamamoto
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data ObjectsWez Furlong
 
Symfony without the framework
Symfony without the frameworkSymfony without the framework
Symfony without the frameworkGOG.com dev team
 

Was ist angesagt? (20)

Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with Jasmine
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
 
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
 
Http4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web StackHttp4s, Doobie and Circe: The Functional Web Stack
Http4s, Doobie and Circe: The Functional Web Stack
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Drupal 8 migrate!
Drupal 8 migrate!Drupal 8 migrate!
Drupal 8 migrate!
 
A Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsA Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP Generators
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to Nodejs
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web services
 
Drupal Render API
Drupal Render APIDrupal Render API
Drupal Render API
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScript
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
 
Symfony without the framework
Symfony without the frameworkSymfony without the framework
Symfony without the framework
 

Andere mochten auch

Booklet a4 (1)
Booklet a4 (1)Booklet a4 (1)
Booklet a4 (1)Edy Wijaya
 
Idj 3 (portfolio)
Idj 3 (portfolio)Idj 3 (portfolio)
Idj 3 (portfolio)Edy Wijaya
 
Características generales de los enfoques cualitativos
Características generales de los enfoques cualitativosCaracterísticas generales de los enfoques cualitativos
Características generales de los enfoques cualitativosNombre Apellidos
 
Productividad y pertinencia en la investigacion universitaria
Productividad y pertinencia en la investigacion universitariaProductividad y pertinencia en la investigacion universitaria
Productividad y pertinencia en la investigacion universitariaNombre Apellidos
 
2012年7月本田美国 (1)
2012年7月本田美国 (1)2012年7月本田美国 (1)
2012年7月本田美国 (1)Lassen Tours
 
Booklet a4 (2)
Booklet a4 (2)Booklet a4 (2)
Booklet a4 (2)Edy Wijaya
 
What to Know Before Visiting the Grand Canyon
What to Know Before Visiting the Grand CanyonWhat to Know Before Visiting the Grand Canyon
What to Know Before Visiting the Grand CanyonLassen Tours
 

Andere mochten auch (8)

Booklet a4 (1)
Booklet a4 (1)Booklet a4 (1)
Booklet a4 (1)
 
Idj 3 (portfolio)
Idj 3 (portfolio)Idj 3 (portfolio)
Idj 3 (portfolio)
 
Idj 4 slide
Idj 4 slideIdj 4 slide
Idj 4 slide
 
Características generales de los enfoques cualitativos
Características generales de los enfoques cualitativosCaracterísticas generales de los enfoques cualitativos
Características generales de los enfoques cualitativos
 
Productividad y pertinencia en la investigacion universitaria
Productividad y pertinencia en la investigacion universitariaProductividad y pertinencia en la investigacion universitaria
Productividad y pertinencia en la investigacion universitaria
 
2012年7月本田美国 (1)
2012年7月本田美国 (1)2012年7月本田美国 (1)
2012年7月本田美国 (1)
 
Booklet a4 (2)
Booklet a4 (2)Booklet a4 (2)
Booklet a4 (2)
 
What to Know Before Visiting the Grand Canyon
What to Know Before Visiting the Grand CanyonWhat to Know Before Visiting the Grand Canyon
What to Know Before Visiting the Grand Canyon
 

Ähnlich wie Persistent Memoization with HTML5 indexedDB and jQuery Promises

IndexedDB - Querying and Performance
IndexedDB - Querying and PerformanceIndexedDB - Querying and Performance
IndexedDB - Querying and PerformanceParashuram N
 
Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)Mike West
 
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6Dmitry Soshnikov
 
Development Approach
Development ApproachDevelopment Approach
Development Approachalexkingorg
 
The Beauty Of Java Script V5a
The Beauty Of Java Script V5aThe Beauty Of Java Script V5a
The Beauty Of Java Script V5arajivmordani
 
jQuery: out with the old, in with the new
jQuery: out with the old, in with the newjQuery: out with the old, in with the new
jQuery: out with the old, in with the newRemy Sharp
 
Node.js for PHP developers
Node.js for PHP developersNode.js for PHP developers
Node.js for PHP developersAndrew Eddie
 
Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}.toster
 
JavaScript for PHP developers
JavaScript for PHP developersJavaScript for PHP developers
JavaScript for PHP developersStoyan Stefanov
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreNicolas Carlo
 
Mongoskin - Guilin
Mongoskin - GuilinMongoskin - Guilin
Mongoskin - GuilinJackson Tian
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSAdam L Barrett
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gearsdion
 
Javascript: the important bits
Javascript: the important bitsJavascript: the important bits
Javascript: the important bitsChris Saylor
 

Ähnlich wie Persistent Memoization with HTML5 indexedDB and jQuery Promises (20)

IndexedDB - Querying and Performance
IndexedDB - Querying and PerformanceIndexedDB - Querying and Performance
IndexedDB - Querying and Performance
 
New in php 7
New in php 7New in php 7
New in php 7
 
Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)
 
The Beauty of Java Script
The Beauty of Java ScriptThe Beauty of Java Script
The Beauty of Java Script
 
Java script for web developer
Java script for web developerJava script for web developer
Java script for web developer
 
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
 
Development Approach
Development ApproachDevelopment Approach
Development Approach
 
The Beauty Of Java Script V5a
The Beauty Of Java Script V5aThe Beauty Of Java Script V5a
The Beauty Of Java Script V5a
 
jQuery: out with the old, in with the new
jQuery: out with the old, in with the newjQuery: out with the old, in with the new
jQuery: out with the old, in with the new
 
Node.js for PHP developers
Node.js for PHP developersNode.js for PHP developers
Node.js for PHP developers
 
Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}
 
JavaScript for PHP developers
JavaScript for PHP developersJavaScript for PHP developers
JavaScript for PHP developers
 
Indexed db
Indexed dbIndexed db
Indexed db
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscore
 
Mongoskin - Guilin
Mongoskin - GuilinMongoskin - Guilin
Mongoskin - Guilin
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
 
Javascript: the important bits
Javascript: the important bitsJavascript: the important bits
Javascript: the important bits
 
JavaScript JQUERY AJAX
JavaScript JQUERY AJAXJavaScript JQUERY AJAX
JavaScript JQUERY AJAX
 

Kürzlich hochgeladen

Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical InfrastructureVarsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructureitnewsafrica
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...itnewsafrica
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observabilityitnewsafrica
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkPixlogix Infotech
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 

Kürzlich hochgeladen (20)

Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical InfrastructureVarsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
React Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App FrameworkReact Native vs Ionic - The Best Mobile App Framework
React Native vs Ionic - The Best Mobile App Framework
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 

Persistent Memoization with HTML5 indexedDB and jQuery Promises

  • 1. R a y B e l l i s @ r a y b e l l i s j Q u e r y U K – 2 0 1 3 / 0 4 / 1 9 1 Persistent Memoization using HTML5 indexedDB and Promises
  • 2. What is Memoization? 2 “Automatic caching of a pure function’s return value, so that a subsequent call with the same parameter(s) obtains the return value from a cache instead of recalculating it.” Avoiding:   Expensive calculations   Repeated AJAX calls…
  • 3. Memoization Example Implementation 3 $.memoize = function(factory, ctx) { var cache = {}; return function(key) { if (!(key in cache)) { cache[key] = factory.call(ctx, key); } return cache[key]; }; };
  • 4. Usage #1 – Expensive Calculations 4 // recursive Fibonacci – O(~1.6^n) !! var fib = function(n) { return (n < 2) ? n : fib(n – 1) + fib(n – 2); } // wrap it fib = $.memoize(fib); The results of recursive calls are delivered from the cache instead of being recalculated. The algorithm improves from O(~1.6^n) to O(n) for first run, and O(1) for previously calculated values of “n”.
  • 5. Usage #2 – Repeated AJAX Calls 5 // AJAX function – returns a “Promise” // expensive to call – may even cost real money! function getGeo(ip) { return $.getJSON(url, {ip: ip}); } // create a wrapped version var memoGeo = $.memoize(getGeo); memoGeo(“192.168.1.1”).done(function(data) { ... }); Repeated calls to the wrapped function for the same input return the same promise, and thus the same result.
  • 6. Usage #2 – Repeated AJAX Calls 6 // AJAX function – returns a “Promise” // expensive to call – may even cost real money! function getGeo(ip) { return $.getJSON(url, {ip: ip}); } // create a wrapped version var memoGeo = $.memoize(getGeo); memoGeo(“192.168.1.1”).done(function(data) { ... }); Repeated calls to the wrapped function for the same input return the same promise, and thus the same result. How could I cache results between sessions?
  • 7. HTML5 “indexedDB” to the Rescue 7   Key/Value Store   Values may be Objects   localStorage only allows Strings   Databases are origin specific (CORS)   Multiple tables (“object stores”) per Database   Asynchronous API   Sync API exists but may be deprecated by W3C   Schema changes require “Database Versioning”
  • 8. Database Versioning 8 $.indexedDB = function(dbname, store) { var version; // initially undefined (function retry() { var request; if (typeof version === "undefined") { request = indexedDB.open(dbname); // open latest version } else { request = indexedDB.open(dbname, version) // or open specific version number } request.onsuccess = function(ev) { var db = ev.target.result; if (!db.objectStoreNames.contains(store)) { // if the store is missing version = db.version + 1; // increment version number db.close(); // close the DB retry(); // and open it again – NB: recursion! } else { // use the database here ... } }; request.onupgradeneeded = function(ev) { var db = ev.target.result; db.createObjectStore(store); // create new table }; })(); // invoke immediately }
  • 9. Callbacks… 9 $.indexedDB = function(dbname, store, callback) { var version; // initially undefined (function retry() { var request; if (typeof version === "undefined") { request = indexedDB.open(dbname); // open latest version } else { request = indexedDB.open(dbname, version) // or open specific version number } request.onsuccess = function(ev) { var db = ev.target.result; if (!db.objectStoreNames.contains(store)) { // if the store is missing version = db.version + 1; // increment version number db.close(); // close the DB retry(); // and open it again – NB: recursion! } else { // use the database here callback(db); } }; request.onupgradeneeded = function(ev) { var db = ev.target.result; db.createObjectStore(store); // create new table }; })(); // invoke immediately }
  • 10. … are so 2010! 10   jQuery Promises   Introduced in jQuery 1.5   Incredibly useful for asynchronous event handling   Rich API   $.when()   .done()   .then()   etc
  • 11. Let’s ditch those callbacks! 11 $.indexedDB = function(dbname, store) { var def = $.Deferred(); // I promise to return ... var version; (function retry() { var request; if (typeof version === "undefined") { request = indexedDB.open(dbname); } else { request = indexedDB.open(dbname, version); } request.onsuccess = function(ev) { var db = ev.target.result; if (!db.objectStoreNames.contains(store)) { version = db.version + 1; db.close(); retry(); } else { // use the database here def.resolve(db); // Tell the caller she can use the DB now } }; request.onupgradeneeded = function(ev) { var db = ev.target.result; db.createObjectStore(store); }; })(); return def.promise(); // I really do promise... };
  • 13. Getting Back to Memoization 13   One Database – avoids naming collisions   One object store per memoized function   Use Promises for consistency with other jQuery async operations No, I didn’t figure all this out in advance!
  • 14. Code Walkthrough 14 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 15. We need to return a function… 15 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 16. that returns a Promise… 16 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 17. and requires a DB connection… 17 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 18. that looks up the key… 18 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 19. and if found, resolves the Promise… 19 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 20. otherwise, calls the original function… 20 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 21. and $.when .done, stores it in the DB… 21 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 22. and asynchronously resolves the Promise 22 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 23. if it can… 23 $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === "undefined") { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, "readwrite").objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; };
  • 24. Persistent Memoization Usage 24 // AJAX function – returns a “Promise” // expensive to call – may even cost real money! function getGeo(ip) { return $.getJSON(url, {ip: ip}); } // create a wrapped version // Object store name is "geoip" and JSON path to key is "ip" var memoGeo = $.memoizeForever(getGeo, "geoip", "ip"); memoGeo("192.168.1.1”).done(function(data) { ... }); Now, repeated calls to the function return previously obtained results, even between browser sessions!