Last active
June 29, 2016 04:12
-
-
Save Jessidhia/df60aaad1be5dba6402ed00fa15de5dc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import $ from 'jquery' | |
// jQuery Deferreds don't have a prototype, so patching them is more complicated | |
// than the native Promises. | |
const origDeferred = $.Deferred | |
const sym = module.hot && module.hot.data | |
? module.hot.data | |
: Symbol('deferred-finally') | |
// throws -- should only be called inside a .then handler | |
function execFinally (func, resolveValue, shouldThrow) { | |
const p = func() | |
// If p is Promise-like | |
if (typeof p.then === 'function') { | |
// Restores the original resolveValue, but only if p doesn't reject | |
return p.then(postFinally) | |
} | |
return postFinally() | |
function postFinally () { | |
if (shouldThrow) { | |
throw resolveValue | |
} | |
return resolveValue | |
} | |
} | |
const finallyPrototype = { | |
finally (func) { | |
func = () => func() | |
// Use .then instead of .always to ensure it behaves like Promise.finally | |
// Rejection in the "catch" branch must always be propagated | |
// Could use Promise.resolve(this).finally, but that would change the type of the result :( | |
return this.then( | |
(v) => execFinally(func, v, false), | |
(e) => execFinally(func, e, true) | |
) | |
} | |
} | |
function patchDeferred (obj) { | |
if (obj[sym]) { | |
return obj | |
} | |
// $.Deferred basically calls self.promise(self) to add promise methods to self | |
const origPromise = obj.promise | |
// Patch .promise to run the original .promise, and patch the resulting promise as well | |
// Because this modifies the parameter, it will work even when called in void context (like inside $.ajax) | |
obj.promise = function promise (...args) { | |
return patchDeferred(origPromise.call(this, ...args)) | |
} | |
if (!obj.finally) { | |
Object.assign(obj, finallyPrototype) | |
} | |
obj[sym] = true | |
return obj | |
} | |
// Replace $.Deferred with a version that patches itself before running the | |
// callback or returning. | |
// | |
// Tested with jQuery 3.0.0. | |
$.Deferred = function Deferred (init = function () {}) { | |
return origDeferred.call(this, /* @this */ function deferred () { | |
patchDeferred(this) | |
init.call(this, this) | |
}) | |
} | |
if (module.hot) { | |
module.hot.accept() | |
module.hot.dispose(() => { | |
$.Deferred = origDeferred | |
return sym | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment