headq
Version:
lightweight javascript promise library
269 lines (207 loc) • 5.76 kB
JavaScript
(function() {
'use strict';
var isArray = Array.isArray;
if (!isArray) {
isArray = function(arg) {
return (Object.prototype.toString.call(arg) === '[object Array]');
};
}
function isFunction(arg) {
return (typeof(arg) === 'function');
}
var delayedCall = null;
if (typeof(window) !== 'undefined') {
if (isFunction(window.setImmediate)) {
delayedCall = window.setImmediate;
}
} else {
if (isFunction(setImmediate)) {
delayedCall = setImmediate;
} else {
if (typeof(process) !== 'undefined' && isFunction(process.nextTick)) {
delayedCall = process.nextTick;
}
}
}
function asyncCall(callback) {
if (isFunction(delayedCall)) {
return delayedCall(callback);
} else {
return setTimeout(callback, 0);
}
}
function Promise() {
}
Promise.prototype.then = function(onResolve, onReject, onNotify) {
var self = this;
if (isFunction(onResolve)) {
if (!isArray(self.onresolve)) {
self.onresolve = [];
}
self.onresolve.push(onResolve);
}
if (isFunction(onReject)) {
if (!isArray(self.onreject)) {
self.onreject = [];
}
self.onreject.push(onReject);
}
if (isFunction(onNotify)) {
if (!isArray(self.onnotify)) {
self.onnotify = [];
}
self.onnotify.push(onNotify);
}
return self;
};
Promise.prototype.catch = function(onError) {
var self = this;
if (isFunction(onError)) {
if (!isArray(self.onreject)) {
self.onreject = [];
}
self.onreject.push(onError);
}
return self;
};
Promise.prototype.finally = function(onResolve, onNotify) {
var self = this;
return self.then(function() {
onResolve();
}, function() {
onResolve();
}, onNotify);
};
function Defer() {
this.promise = new Promise();
}
Defer.prototype.then = function(onResolve, onReject, onNotify) {
return this.promise.then(onResolve, onReject, onNotify);
};
Defer.prototype.catch = function(onError) {
return this.promise.catch(onError);
};
Defer.prototype.finally = function(onResolve, onNotify) {
return this.promise.finally(onResolve, onNotify);
};
Defer.prototype.resolve = function(arg) {
var self = this;
asyncCall(function() {
if (isArray(self.promise.onresolve) && !self.rejected) {
var callbacks = self.promise.onresolve;
callbacks.forEach(function(callback) {
try {
callback.call(self, arg);
} catch(ignored) {}
});
self.promise.onresolve = null;
self.promise.onreject = null;
self.promise.onnotify = null;
}
});
return self.promise;
};
Defer.prototype.reject = function(arg) {
var self = this;
self.rejected = true;
asyncCall(function() {
if (isArray(self.promise.onreject)) {
var callbacks = self.promise.onreject;
callbacks.forEach(function(callback) {
try {
callback.call(self, arg);
} catch(ignored) {}
});
}
self.promise.onresolve = null;
self.promise.onreject = null;
self.promise.onnotify = null;
});
return self.promise;
};
Defer.prototype.notify = function(arg) {
var self = this;
asyncCall(function() {
if (isArray(self.promise.onnotify)) {
var callbacks = self.promise.onnotify;
callbacks.forEach(function(callback) {
try {
callback.call(self, arg);
} catch(ignored) {}
});
}
});
};
var $q = function(callback) {
var req = new Defer();
function onResolve(data) {
req.resolve(data);
}
function onReject(data) {
req.reject(data);
}
function onNotify(data) {
req.notify(data);
}
asyncCall(function() {
try {
callback(onResolve, onReject, onNotify);
} catch(error) {
req.reject(error);
}
});
return req.promise;
}
$q.defer = function() {
return new Defer();
};
$q.when = function(arg, onResolve, onReject, onNotify) {
if (arg && isFunction(arg.then)) {
return arg.then.call(arg, onResolve, onReject, onNotify);
}
var req = new Defer();
req.resolve(arg);
return req.promise;
};
$q.resolve = $q.when;
$q.reject = function(arg) {
var req = new Defer();
req.reject(arg);
return req.promise;
};
$q.all = function(targets) {
var req = new Defer();
var list = targets;
var res = [];
var len = 0;
if (targets instanceof Promise) {
list = [ targets ];
}
try {
len = list.length;
if (len) {
list.forEach(function(promise, index) {
promise.then(function(arg) {
len--;
res[index] = arg;
if (!len) {
req.resolve(res);
}
}, function(error) {
req.reject(error);
});
});
} else {
req.resolve([]);
}
} catch (error) {
req.reject(error);
}
return req.promise;
};
if (typeof(exports) !== 'undefined') {
module.exports = $q;
} else {
window.$q = $q;
}
})();