├── .bowerrc
├── .gitattributes
├── Makefile
├── README.md
├── bower.json
├── example.html
├── js
├── deferred.js
└── deferred.min.js
├── node_module
└── jq-deferred.js
└── package.json
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "registry": "https://registry.bower.io"
3 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # npm install uglify-js -g
2 | minify:
3 | uglifyjs -o js/deferred.min.js js/deferred.js
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | deferred-js
2 | ===========
3 |
4 | deferred-js is a light (less than 1 kb gzipped) standalone implementation of promise/deferred that aims to be fully compatible with $.Deferred found in [jQuery 1.5+] (http://api.jquery.com/category/deferred-object/).
5 |
6 |
7 | What's implemented ?
8 | --------------------
9 |
10 | * Deferred.always
11 | * Deferred.done
12 | * Deferred.fail
13 | * Deferred.isRejected
14 | * Deferred.isResolved
15 | * Deferred.notify
16 | * Deferred.notifyWith
17 | * Deferred.progress
18 | * Deferred.promise
19 | * Deferred.reject
20 | * Deferred.rejectWith
21 | * Deferred.resolve
22 | * Deferred.resolveWith
23 | * Deferred.state
24 | * Deferred.then
25 | * Deferred.when
26 |
27 |
28 | What's Missing ?
29 | ----------------
30 |
31 | * Deferred.pipe
32 |
33 |
34 | Setup
35 | -----
36 |
37 | #### Using nodejs
38 | * type in a terminal: `npm install deferred-js`
39 | * require deferred-js: `var Deferred = require('deferred-js');`
40 |
41 | #### Using a browser
42 | * include the deferred script: ``
43 | * Deferred is available inside the global object
44 |
45 | Example
46 | -------
47 |
48 | // Create a Deferred and return its Promise
49 | function asyncEvent(){
50 | var dfd = new Deferred();
51 | setTimeout(function(){
52 | dfd.resolve("hurray");
53 | }, Math.floor(Math.random()*1500));
54 | setTimeout(function(){
55 | dfd.reject("sorry");
56 | }, Math.floor(Math.random()*1500));
57 | return dfd.promise();
58 | }
59 |
60 | // Attach a done and fail handler for the asyncEvent
61 | Deferred.when(asyncEvent()).then(
62 | function(status){
63 | console.log( status+', things are going well' );
64 | },
65 | function(status){
66 | console.log( status+', you fail this time' );
67 | }
68 | );
69 |
70 | Licence
71 | -------
72 |
73 | This software is distributed under an MIT licence.
74 |
75 | Copyright 2012 © Nicolas Ramz
76 |
77 | > Permission is hereby granted, free of charge, to any person obtaining a copy of this software
78 | > and associated documentation files (the "Software"), to deal in the Software without
79 | > restriction, including without limitation the rights to use, copy, modify, merge, publish,
80 | > distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
81 | > Software is furnished to do so, subject to the following conditions:
82 | > The above copyright notice and this permission notice shall be included in all copies or
83 | > substantial portions of the Software.
84 | > The Software is provided "as is", without warranty of any kind, express or implied, including
85 | > but not limited to the warranties of merchantability, fitness for a particular purpose and
86 | > noninfringement. In no event shall the authors or copyright holders be liable for any claim,
87 | > damages or other liability, whether in an action of contract, tort or otherwise, arising from,
88 | > out of or in connection with the software or the use or other dealings in the Software.
89 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "deferred-js",
3 | "version": "1.0.4",
4 | "main": "js/deferred.min.js",
5 | "ignore": [
6 | "node_module",
7 | ".gitattributes",
8 | ".gitignore",
9 | "Makefile",
10 | "example.html",
11 | "bower.json",
12 | "package.json",
13 | "README.md"
14 | ],
15 | "homepage": "https://github.com/warpdesign/deferred-js",
16 | "authors": [
17 | "Nicolas Ramz (http://nicolasramz.fr)"
18 | ]
19 | }
--------------------------------------------------------------------------------
/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 |
16 |
17 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/js/deferred.js:
--------------------------------------------------------------------------------
1 | (function(global) {
2 | function isArray(arr) {
3 | return Object.prototype.toString.call(arr) === '[object Array]';
4 | }
5 |
6 | function foreach(arr, handler) {
7 | if (isArray(arr)) {
8 | for (var i = 0; i < arr.length; i++) {
9 | handler(arr[i]);
10 | }
11 | }
12 | else
13 | handler(arr);
14 | }
15 |
16 | function D(fn) {
17 | var status = 'pending',
18 | doneFuncs = [],
19 | failFuncs = [],
20 | progressFuncs = [],
21 | resultArgs = null,
22 |
23 | promise = {
24 | done: function() {
25 | for (var i = 0; i < arguments.length; i++) {
26 | // skip any undefined or null arguments
27 | if (!arguments[i]) {
28 | continue;
29 | }
30 |
31 | if (isArray(arguments[i])) {
32 | var arr = arguments[i];
33 | for (var j = 0; j < arr.length; j++) {
34 | // immediately call the function if the deferred has been resolved
35 | if (status === 'resolved') {
36 | arr[j].apply(this, resultArgs);
37 | }
38 |
39 | doneFuncs.push(arr[j]);
40 | }
41 | }
42 | else {
43 | // immediately call the function if the deferred has been resolved
44 | if (status === 'resolved') {
45 | arguments[i].apply(this, resultArgs);
46 | }
47 |
48 | doneFuncs.push(arguments[i]);
49 | }
50 | }
51 |
52 | return this;
53 | },
54 |
55 | fail: function() {
56 | for (var i = 0; i < arguments.length; i++) {
57 | // skip any undefined or null arguments
58 | if (!arguments[i]) {
59 | continue;
60 | }
61 |
62 | if (isArray(arguments[i])) {
63 | var arr = arguments[i];
64 | for (var j = 0; j < arr.length; j++) {
65 | // immediately call the function if the deferred has been resolved
66 | if (status === 'rejected') {
67 | arr[j].apply(this, resultArgs);
68 | }
69 |
70 | failFuncs.push(arr[j]);
71 | }
72 | }
73 | else {
74 | // immediately call the function if the deferred has been resolved
75 | if (status === 'rejected') {
76 | arguments[i].apply(this, resultArgs);
77 | }
78 |
79 | failFuncs.push(arguments[i]);
80 | }
81 | }
82 |
83 | return this;
84 | },
85 |
86 | always: function() {
87 | return this.done.apply(this, arguments).fail.apply(this, arguments);
88 | },
89 |
90 | progress: function() {
91 | for (var i = 0; i < arguments.length; i++) {
92 | // skip any undefined or null arguments
93 | if (!arguments[i]) {
94 | continue;
95 | }
96 |
97 | if (isArray(arguments[i])) {
98 | var arr = arguments[i];
99 | for (var j = 0; j < arr.length; j++) {
100 | // immediately call the function if the deferred has been resolved
101 | if (status === 'pending') {
102 | progressFuncs.push(arr[j]);
103 | }
104 | }
105 | }
106 | else {
107 | // immediately call the function if the deferred has been resolved
108 | if (status === 'pending') {
109 | progressFuncs.push(arguments[i]);
110 | }
111 | }
112 | }
113 |
114 | return this;
115 | },
116 |
117 | then: function() {
118 | // fail callbacks
119 | if (arguments.length > 1 && arguments[1]) {
120 | this.fail(arguments[1]);
121 | }
122 |
123 | // done callbacks
124 | if (arguments.length > 0 && arguments[0]) {
125 | this.done(arguments[0]);
126 | }
127 |
128 | // notify callbacks
129 | if (arguments.length > 2 && arguments[2]) {
130 | this.progress(arguments[2]);
131 | }
132 | },
133 |
134 | promise: function(obj) {
135 | if (obj == null) {
136 | return promise;
137 | } else {
138 | for (var i in promise) {
139 | obj[i] = promise[i];
140 | }
141 | return obj;
142 | }
143 | },
144 |
145 | state: function() {
146 | return status;
147 | },
148 |
149 | debug: function() {
150 | console.log('[debug]', doneFuncs, failFuncs, status);
151 | },
152 |
153 | isRejected: function() {
154 | return status === 'rejected';
155 | },
156 |
157 | isResolved: function() {
158 | return status === 'resolved';
159 | },
160 |
161 | pipe: function(done, fail, progress) {
162 | return D(function(def) {
163 | foreach(done, function(func) {
164 | // filter function
165 | if (typeof func === 'function') {
166 | deferred.done(function() {
167 | var returnval = func.apply(this, arguments);
168 | // if a new deferred/promise is returned, its state is passed to the current deferred/promise
169 | if (returnval && typeof returnval === 'function') {
170 | returnval.promise().then(def.resolve, def.reject, def.notify);
171 | }
172 | else { // if new return val is passed, it is passed to the piped done
173 | def.resolve(returnval);
174 | }
175 | });
176 | }
177 | else {
178 | deferred.done(def.resolve);
179 | }
180 | });
181 |
182 | foreach(fail, function(func) {
183 | if (typeof func === 'function') {
184 | deferred.fail(function() {
185 | var returnval = func.apply(this, arguments);
186 |
187 | if (returnval && typeof returnval === 'function') {
188 | returnval.promise().then(def.resolve, def.reject, def.notify);
189 | } else {
190 | def.reject(returnval);
191 | }
192 | });
193 | }
194 | else {
195 | deferred.fail(def.reject);
196 | }
197 | });
198 | }).promise();
199 | }
200 | },
201 |
202 | deferred = {
203 | resolveWith: function(context) {
204 | if (status === 'pending') {
205 | status = 'resolved';
206 | var args = resultArgs = (arguments.length > 1) ? arguments[1] : [];
207 | for (var i = 0; i < doneFuncs.length; i++) {
208 | doneFuncs[i].apply(context, args);
209 | }
210 | }
211 | return this;
212 | },
213 |
214 | rejectWith: function(context) {
215 | if (status === 'pending') {
216 | status = 'rejected';
217 | var args = resultArgs = (arguments.length > 1) ? arguments[1] : [];
218 | for (var i = 0; i < failFuncs.length; i++) {
219 | failFuncs[i].apply(context, args);
220 | }
221 | }
222 | return this;
223 | },
224 |
225 | notifyWith: function(context) {
226 | if (status === 'pending') {
227 | var args = resultArgs = (arguments.length > 1) ? arguments[1] : [];
228 | for (var i = 0; i < progressFuncs.length; i++) {
229 | progressFuncs[i].apply(context, args);
230 | }
231 | }
232 | return this;
233 | },
234 |
235 | resolve: function() {
236 | return this.resolveWith(this, arguments);
237 | },
238 |
239 | reject: function() {
240 | return this.rejectWith(this, arguments);
241 | },
242 |
243 | notify: function() {
244 | return this.notifyWith(this, arguments);
245 | }
246 | }
247 |
248 | var obj = promise.promise(deferred);
249 |
250 | if (fn) {
251 | fn.apply(obj, [obj]);
252 | }
253 |
254 | return obj;
255 | }
256 |
257 | D.when = function() {
258 | if (arguments.length < 2) {
259 | var obj = arguments.length ? arguments[0] : undefined;
260 | if (obj && (typeof obj.isResolved === 'function' && typeof obj.isRejected === 'function')) {
261 | return obj.promise();
262 | }
263 | else {
264 | return D().resolve(obj).promise();
265 | }
266 | }
267 | else {
268 | return (function(args){
269 | var df = D(),
270 | size = args.length,
271 | done = 0,
272 | rp = new Array(size); // resolve params: params of each resolve, we need to track down them to be able to pass them in the correct order if the master needs to be resolved
273 |
274 | for (var i = 0; i < args.length; i++) {
275 | (function(j) {
276 | var obj = null;
277 |
278 | if (args[j].done) {
279 | args[j].done(function() { rp[j] = (arguments.length < 2) ? arguments[0] : arguments; if (++done == size) { df.resolve.apply(df, rp); }})
280 | .fail(function() { df.reject(arguments); });
281 | } else {
282 | obj = args[j];
283 | args[j] = new Deferred();
284 |
285 | args[j].done(function() { rp[j] = (arguments.length < 2) ? arguments[0] : arguments; if (++done == size) { df.resolve.apply(df, rp); }})
286 | .fail(function() { df.reject(arguments); }).resolve(obj);
287 | }
288 | })(i);
289 | }
290 |
291 | return df.promise();
292 | })(arguments);
293 | }
294 | }
295 |
296 | global.Deferred = D;
297 | })(window);
--------------------------------------------------------------------------------
/js/deferred.min.js:
--------------------------------------------------------------------------------
1 | !function(global){function isArray(arr){return"[object Array]"===Object.prototype.toString.call(arr)}function foreach(arr,handler){if(isArray(arr))for(var i=0;i1&&arguments[1]&&this.fail(arguments[1]),arguments.length>0&&arguments[0]&&this.done(arguments[0]),arguments.length>2&&arguments[2]&&this.progress(arguments[2])},promise:function(obj){if(null==obj)return promise;for(var i in promise)obj[i]=promise[i];return obj},state:function(){return status},debug:function(){console.log("[debug]",doneFuncs,failFuncs,status)},isRejected:function(){return"rejected"===status},isResolved:function(){return"resolved"===status},pipe:function(done,fail){return D(function(def){foreach(done,function(func){"function"==typeof func?deferred.done(function(){var returnval=func.apply(this,arguments);returnval&&"function"==typeof returnval?returnval.promise().then(def.resolve,def.reject,def.notify):def.resolve(returnval)}):deferred.done(def.resolve)}),foreach(fail,function(func){"function"==typeof func?deferred.fail(function(){var returnval=func.apply(this,arguments);returnval&&"function"==typeof returnval?returnval.promise().then(def.resolve,def.reject,def.notify):def.reject(returnval)}):deferred.fail(def.reject)})}).promise()}},deferred={resolveWith:function(context){if("pending"===status){status="resolved";for(var args=resultArgs=arguments.length>1?arguments[1]:[],i=0;i1?arguments[1]:[],i=0;i1?arguments[1]:[],i=0;i 1 && arguments[1]) {
138 | // this.fail(arguments[1]);
139 | // }
140 | //
141 | // // done callbacks
142 | // if (arguments.length > 0 && arguments[0]) {
143 | // this.done(arguments[0]);
144 | // }
145 | //
146 | // // notify callbacks
147 | // if (arguments.length > 2 && arguments[2]) {
148 | // this.progress(arguments[2]);
149 | // }
150 | //
151 | // return this;
152 | // },
153 |
154 | promise: function(obj) {
155 | if (obj == null) {
156 | return promise;
157 | } else {
158 | for (var i in promise) {
159 | obj[i] = promise[i];
160 | }
161 | return obj;
162 | }
163 | },
164 |
165 | state: function() {
166 | return status;
167 | },
168 |
169 | debug: function() {
170 | console.log('id', thisId);
171 | console.log('[debug]', doneFuncs, failFuncs, status);
172 | },
173 |
174 | isRejected: function() {
175 | return status === 'rejected';
176 | },
177 |
178 | isResolved: function() {
179 | return status === 'resolved';
180 | },
181 |
182 | pipe: function(done, fail, progress) {
183 | var newDef = D(function(def) {
184 | var that = this;
185 | foreach(done || null, function(func) {
186 | // filter function
187 | if (typeof func === 'function') {
188 | deferred.done(function() {
189 | var returnval = func.apply(this, arguments);
190 | // if a new deferred/promise is returned, its state is passed to the current deferred/promise
191 | if (returnval && typeof returnval.promise === 'function') {
192 | returnval.promise().done(def.resolve).fail(def.reject).progress(def.notify);
193 | }
194 | else { // if new return val is passed, it is passed to the piped done
195 | def.resolveWith(this === promise ? def.promise() : this, [returnval]);
196 | }
197 | }.bind(that));
198 | } else {
199 | deferred.done(def.resolve);
200 | }
201 | });
202 |
203 | foreach(fail || null, function(func) {
204 | if (typeof func === 'function') {
205 | deferred.fail(function() {
206 | var returnval = func.apply(this, arguments);
207 |
208 | if (returnval && typeof returnval.promise === 'function') {
209 | returnval.promise().done(def.resolve).fail(def.reject).progress(def.notify);
210 | } else {
211 | def.rejectWith(this === promise ? def.promise() : this, [returnval]);
212 | }
213 | }.bind(that));
214 | }
215 | else {
216 | deferred.fail(def.reject);
217 | }
218 | });
219 |
220 | foreach(progress || null, function(func) {
221 | if (typeof func === 'function') {
222 | deferred.progress(function() {
223 | var returnval = func.apply(this, arguments);
224 |
225 | if (returnval && typeof returnval.promise === 'function') {
226 | returnval.promise().done(def.resolve).fail(def.reject).progress(def.notify);
227 | } else {
228 | def.notifyWith(this === promise ? def.promise() : this, [returnval]);
229 | }
230 | }.bind(that));
231 | }
232 | else {
233 | deferred.progress(def.notify);
234 | }
235 | });
236 | });
237 |
238 | return newDef.promise();
239 | },
240 |
241 | getContext: function() {
242 | return context;
243 | },
244 |
245 | getId: function() {
246 | return thisId;
247 | }
248 | },
249 |
250 | deferred = {
251 | resolveWith: function(ctx) {
252 | if (status === 'pending') {
253 | status = 'resolved';
254 | var args = resultArgs = (arguments.length > 1) ? arguments[1] : [];
255 | for (var i = 0; i < doneFuncs.length; i++) {
256 | doneFuncs[i].apply(ctx, args);
257 | }
258 | }
259 |
260 | // context = ctx;
261 |
262 | return this;
263 | },
264 |
265 | rejectWith: function(ctx) {
266 | if (status === 'pending') {
267 | status = 'rejected';
268 | var args = resultArgs = (arguments.length > 1) ? arguments[1] : [];
269 | for (var i = 0; i < failFuncs.length; i++) {
270 | failFuncs[i].apply(ctx, args);
271 | }
272 | }
273 |
274 | // context = ctx;
275 |
276 | return this;
277 | },
278 |
279 | notifyWith: function(ctx) {
280 | var args;
281 |
282 | if (status === 'pending') {
283 | args = lastNotify = (arguments.length > 1) ? arguments[1] : [];
284 | for (var i = 0; i < progressFuncs.length; i++) {
285 | progressFuncs[i].apply(ctx, args);
286 | }
287 |
288 | // context = ctx;
289 | }
290 |
291 | return this;
292 | },
293 |
294 | resolve: function() {
295 | var ret = deferred.resolveWith(this === deferred ? promise : this, arguments);
296 | return this !== deferred ? this : ret;
297 | },
298 |
299 | reject: function() {
300 | var ret = deferred.rejectWith(this === deferred ? promise : this, arguments);
301 | return this !== deferred ? this : ret;
302 | },
303 |
304 | notify: function() {
305 | var ret = deferred.notifyWith(this === deferred ? promise : this, arguments);
306 | return this !== deferred ? this : ret;
307 | }
308 | }
309 |
310 | promise.then = promise.pipe;
311 |
312 | var obj = promise.promise(deferred);
313 |
314 | context = obj;
315 |
316 | obj.id = deferred.id = thisId;
317 |
318 | if (fn) {
319 | fn.apply(obj, [obj]);
320 | }
321 |
322 | return obj;
323 | };
324 |
325 | D.when = function() {
326 | if (arguments.length < 2) {
327 | var obj = arguments.length ? arguments[0] : undefined;
328 | if (obj && (typeof obj.isResolved === 'function' && typeof obj.isRejected === 'function')) {
329 | return obj.promise();
330 | }
331 | else {
332 | return D().resolveWith(window, [obj]).promise();
333 | }
334 | }
335 | else {
336 | return (function(args){
337 | var df = D(),
338 | size = args.length,
339 | done = 0,
340 | rp = new Array(size), // resolve params: params of each resolve, we need to track down them to be able to pass them in the correct order if the master needs to be resolved
341 | pp = new Array(size),
342 | whenContext = [];
343 |
344 | for (var i = 0; i < args.length; i++) {
345 | whenContext[i] = args[i] && args[i].promise ? args[i].promise() : undefined;
346 | (function(j) {
347 | var obj = null;
348 |
349 | if (args[j].done) {
350 | args[j].done(function() { rp[j] = (arguments.length < 2) ? arguments[0] : arguments; if (++done == size) { df.resolve.apply(whenContext, rp); }})
351 | .fail(function() { df.reject.apply(whenContext, arguments); });
352 | } else {
353 | obj = args[j];
354 | args[j] = new Deferred();
355 |
356 | args[j].done(function() { rp[j] = (arguments.length < 2) ? arguments[0] : arguments; if (++done == size) { df.resolve.apply(whenContext, rp); }})
357 | .fail(function() { df.reject.apply(whenContext, arguments); }).resolve(obj);
358 | }
359 |
360 | args[j].progress(function() {
361 | pp[j] = (arguments.length < 2) ? arguments[0] : arguments;
362 | df.notify.apply(whenContext, pp);
363 | });
364 | })(i);
365 | }
366 |
367 | return df.promise();
368 | })(arguments);
369 | }
370 | }
371 |
372 | return D;
373 | })({});
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "deferred-js",
3 | "version": "1.0.3",
4 | "description": "Light (less than 1 kb gzipped) standalone implementation of promise/deferred that aims to be fully compatible with $.Deferred found in jQuery 1.5+.",
5 | "main": "node_module/jq-deferred.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/warpdesign/Standalone-Deferred.git"
12 | },
13 | "keywords": [
14 | "deferred",
15 | "promise",
16 | "jquery"
17 | ],
18 | "author": "Nicolas Ramz",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/warpdesign/Standalone-Deferred/issues"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------