2017年8月11日 星期五
Promise 擴增,與 簡單的 $Deferred
(function () {
if (typeof Promise !== 'function') {
throw new Error('need Promise');
}
/*------------------------------------------------------------------------*/
// promise.done()
if (typeof Promise.prototype.done === 'undefined') {
Promise.prototype.done = function (onFulfilled) {
return this.then(onFulfilled, undefined);
};
}
// promise.doneWith()
if (typeof Promise.prototype.doneWith === 'undefined') {
Promise.prototype.doneWith = function (onFulfilled, context) {
onFulfilled = onFulfilled.bind(context);
return this.then(onFulfilled, undefined);
};
}
/*------------------------------------------------------------------------*/
// promise.catchWith()
if (typeof Promise.prototype.catchWith === 'undefined') {
Promise.prototype.catchWith = function (onRejected, context) {
onRejected = onRejected.bind(context);
return this.then(undefined, onRejected);
};
}
/*------------------------------------------------------------------------*/
// promise.always()
if (typeof Promise.prototype.always === 'undefined') {
Promise.prototype.always = function (callback) {
return this.then(function (data) {
callback(false, data);
}, function (error) {
callback(true, error);
});
};
}
// promise.alwaysWith()
if (typeof Promise.prototype.alwaysWith === 'undefined') {
Promise.prototype.alwaysWith = function (callback, context) {
callback = callback.bind(this);
return this.then(function (data) {
callback(false, data);
}, function (error) {
callback(true, error);
});
};
}
/*------------------------------------------------------------------------*/
// setImmediate => process => setTimeout
var async = typeof setImmediate !== 'undefined' ?
(function (fn) {
setImmediate(fn);
}) : (typeof process !== 'undefined' && process.nextTick ?
process.nextTick :
function (fn) {
setTimeout(fn, 0);
});
/*------------------------------------------------------------------------*/
if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = $Deferred;
} else if (typeof window === 'object') {
window.$Deferred = window.$Deferred || $Deferred;
}
/*------------------------------------------------------------------------*/
function $Deferred() {
if (this === window) {
return new $Deferred();
}
var self = this;
this._reject;
this._resolve;
this._promise = new Promise(function (resolve, reject) {
self._resolve = resolve;
self._reject = reject;
});
}
(function () {
this.p = this.promise = function () {
return this._promise;
};
/**********************************************************************/
this.resolve = function (arg, nextTick) {
var self = this;
if (nextTick != null && nextTick === true) {
var job = (function () {
// 避免某些情況有些瀏覽器會叫
this._resolve(arg);
}).bind(this);
async(job);
} else {
this._resolve(arg);
}
};
/**********************************************************************/
this.reject = function (arg, nextTick) {
var self = this;
if (nextTick != null && nextTick === true) {
var job = (function () {
// 避免某些情況有些瀏覽器會叫
this._reject(arg);
}).bind(this);
async(job);
} else {
this._reject(arg);
}
};
/**********************************************************************/
this.then = function (onFulfilled, onRejected) {
var def = $Deferred();
var p = this.promise();
p = p.then(function (data) {
return onFulfilled(data);
}, function (error) {
return onRejected(error);
});
/*--------------------------*/
p.then(function (data) {
def.resolve(data);
}, function (error) {
def.reject(error);
});
return def;
};
this.thenWith = function (onFulfilled, onRejected, context) {
onFulfilled = onFulfilled.bind(context);
onRejected = onRejected.bind(context);
var def = $Deferred();
var p = this.promise();
p = p.then(function (data) {
return onFulfilled(data);
}, function (error) {
return onRejected(error);
});
/*--------------------------*/
p.then(function (data) {
def.resolve(data);
}, function (error) {
def.reject(error);
});
return def;
};
/**********************************************************************/
this.done = function (onFulfilled) {
var def = $Deferred();
var p = this.promise();
p = p.then(function (data) {
return onFulfilled(data);
}, undefined);
/*--------------------------*/
p.then(function (data) {
def.resolve(data);
}, function (error) {
def.reject(error);
});
return def;
};
this.doneWith = function (onFulfilled, context) {
onFulfilled = onFulfilled.bind(context);
var def = $Deferred();
var p = this.promise();
p = p.then(function (data) {
return onFulfilled(data);
}, undefined);
/*--------------------------*/
p.then(function (data) {
def.resolve(data);
}, function (error) {
def.reject(error);
});
return def;
};
/**********************************************************************/
this.catch = function (onRejected) {
var def = $Deferred();
var p = this.promise();
p = p.catch(function (error) {
return onRejected(error);
});
/*--------------------------*/
p.then(function (data) {
def.resolve(data);
}, function (error) {
def.reject(error);
});
return def;
};
this.catchWith = function (onRejected, context) {
onRejected = onRejected.bind(context);
var def = $Deferred();
var p = this.promise();
p = p.catch(function (error) {
return onRejected(error);
});
/*--------------------------*/
p.then(function (data) {
def.resolve(data);
}, function (error) {
def.reject(error);
});
return def;
};
/**********************************************************************/
this.always = function (callback) {
var def = $Deferred();
var p = this.promise();
p = p.then(function (data) {
return callback(false, data);
}, function (error) {
return callback(true, error);
});
/*--------------------------*/
p.then(function (data) {
def.resolve(data);
}, function (error) {
def.reject(error);
});
return def;
};
this.alwaysWith = function (callback, context) {
callback = callback.binf(context);
var def = $Deferred();
var p = this.promise();
p = p.then(function (data) {
return callback(false, data);
}, function (error) {
return callback(true, error);
});
/*--------------------------*/
p.then(function (data) {
def.resolve(data);
}, function (error) {
def.reject(error);
});
return def;
};
}).call($Deferred.prototype);
})();