forked from klassennetz/backbone.speed_cache
-
Notifications
You must be signed in to change notification settings - Fork 0
/
backbone.memoized_sync.js
149 lines (132 loc) · 4.72 KB
/
backbone.memoized_sync.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//
// Backbone.memoized_sync 0.1.0
// ==========================
//
// Made by Pablo Villalba for the Teambox project
// May be freely distributed under the MIT license
//
//
// What does Backbone.memoized_sync solve
// --------------------------------------
//
// The default Backbone.sync sends an AJAX request every time. When an app needs to
// request too much data to start up, the UX can suffer.
//
// This modified version changes the behavior for 'read' requests to the following:
//
// 1. Check if we have it in localStorage.
// 2. If we have it, then...
// - We call the success function with the cached data
// - We request new data with an AJAX request, which calls the success function again
// 3. If we don't have it, we do a classic AJAX request and save its results to localStorage
//
//
// How to enabled memoized sync for your models and collections
// ------------------------------------------------------------
//
// You must define your model's or collection's sync to be Backbone.memoized_sync:
//
// this.sync = Backbone.memoized_sync;
//
// That's it! Now every GET request will be written to localStorage and retrieved
// from there the next time you request it.
//
//
// Handling multiple sessions or users
// -----------------------------------
//
// In order to use this with per-session caches, you will need to define the
// *cache_namespace* attribute in your models and collections. The sync method will
// store the results of successful calls in "#{cache_namespace}/#{requested_url}"
//
// If you are caching sensitive data, remember to clear localStorage when logging out
// or when loggin in with a different user.
//
//
// Targeted Backbone versions
// --------------------------
// This modified Backbone.sync targets Backbone 0.5.3.
//
(function () {
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
var methodMap = {
'create': 'POST',
'update': 'PUT',
'delete': 'DELETE',
'read' : 'GET'
};
// Helper function to get a URL from a Model or Collection as a property
// or as a function.
var getUrl = function(object) {
if (!(object && object.url)) return null;
return _.isFunction(object.url) ? object.url() : object.url;
};
// Ported from Modernizr
function supports_local_storage() {
try {
return 'localStorage' in window && window.localStorage !== null;
} catch (e) {
return false;
}
}
Backbone.memoized_sync = function (method, model, options) {
var type = methodMap[method];
// Default JSON-request options.
var params = _.extend({
type: type,
dataType: 'json'
}, options);
// Ensure that we have a URL.
if (!params.url) {
params.url = getUrl(model) || urlError();
}
// Ensure that we have the appropriate request data.
if (!params.data && model && (method == 'create' || method == 'update')) {
params.contentType = 'application/json';
params.data = JSON.stringify(model.toJSON());
}
// For older servers, emulate JSON by encoding the request into an HTML-form.
if (Backbone.emulateJSON) {
params.contentType = 'application/x-www-form-urlencoded';
params.data = params.data ? {model : params.data} : {};
}
// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
// And an `X-HTTP-Method-Override` header.
if (Backbone.emulateHTTP) {
if (type === 'PUT' || type === 'DELETE') {
if (Backbone.emulateJSON) params.data._method = type;
params.type = 'POST';
params.beforeSend = function(xhr) {
xhr.setRequestHeader('X-HTTP-Method-Override', type);
};
}
}
// Don't process data on a non-GET request.
if (params.type !== 'GET' && !Backbone.emulateJSON) {
params.processData = false;
}
// This is the modified part:
// - Look for the cached version and trigger success if it's present.
// - Modify the AJAX request so it'll save the data on success.
if (method === 'read' && supports_local_storage()) {
// Look for the cached version
var namespace = model.cache_namespace || "_",
key = "backbone-cache/" + namespace + "/" + params.url,
val = localStorage.getItem(key),
successFn = params.success;
// If we have the last response cached, use it with the success callback
if (val) {
_.defer(function () {
successFn(JSON.parse(val), "success");
});
}
// Overwrite the success callback to save data to localStorage
params.success = function (resp, status, xhr) {
successFn(resp, status, xhr);
localStorage.setItem(key, xhr.responseText);
};
}
// Make the request.
return $.ajax(params);
};
}).call(this);