Created
January 20, 2018 11:35
-
-
Save kerbyfc/9da1f2bf32d527b65215e4b596bc1256 to your computer and use it in GitHub Desktop.
This file contains 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
function Futures(executor) { | |
const self = this; | |
let fullfilled = false; | |
let pending = true; | |
let rejected = false; | |
let data; | |
const callbacks = { | |
resolve: null, | |
reject: null | |
}; | |
const pipe = { | |
resolve: null, | |
reject: null, | |
} | |
const resolve = function (value) { | |
pending = false; | |
data = value; | |
if (!rejected) { | |
fullfilled = true; | |
if (typeof callbacks.resolve === 'function') { | |
return callbacks.resolve(data); | |
} | |
} | |
}; | |
const reject = function (value) { | |
pending = false; | |
data = value; | |
if (!fullfilled) { | |
rejected = true; | |
if (typeof callbacks.reject === 'function') { | |
return callbacks.reject(data); | |
} | |
} | |
} | |
const thenable = { | |
then: function(resolveCallback, rejectCallback) { | |
return Futures(function(resolve, reject) { | |
callbacks.resolve = Futures.pipe(resolveCallback, resolve, reject); | |
callbacks.reject = rejectCallback; | |
if (fullfilled) { | |
callbacks.resolve(data); | |
} | |
if (rejected) { | |
callbacks.reject(data); | |
} | |
}); | |
} | |
}; | |
Object.defineProperties(thenable, { | |
fullfilled: { | |
enumerable: true, | |
get: function() { | |
return fullfilled; | |
} | |
}, | |
rejected: { | |
enumerable: true, | |
get: function() { | |
return rejected; | |
} | |
}, | |
pending: { | |
enumerable: true, | |
get: function() { | |
return pending; | |
} | |
} | |
}); | |
setTimeout(function() { | |
executor(resolve, reject); | |
}, 0); | |
return thenable; | |
} | |
Futures.isThenable = function (value) { | |
return value && typeof value.then === 'function'; | |
} | |
Futures.pipe = function (parentResolve, pipedResolve, pipedReject) { | |
return function (value) { | |
const parentResolveCallbackResult = parentResolve(value); | |
if (Futures.isThenable(parentResolveCallbackResult)) { | |
return parentResolveCallbackResult.then(pipedResolve, pipedReject); | |
} | |
return new Futures(function (resolve) { | |
resolve(pipedResolve(parentResolveCallbackResult)); | |
}); | |
}; | |
} | |
// Тест #1 | |
var foo = new Futures(function (resolve, reject) { | |
resolve.call(this, 123); | |
}); | |
foo.then(function (val) { | |
console.log("foo.resolved:", val === 123); | |
}, function () { | |
console.log("foo.resolved: fail"); | |
}); | |
// Тест #2 | |
var bar = new Futures(function (resolve, reject) { | |
setTimeout(resolve.bind(null, "fail"), 300); | |
setTimeout(reject.bind(null, "ok"), 200); | |
}); | |
bar.then(function () { | |
console.log("bar.rejected: fail"); | |
}, function (val) { | |
console.log("bar.rejected:", val === "ok"); | |
}); | |
// Дополнительно | |
setTimeout(function() { | |
console.log('foo', foo); | |
console.log('bar', bar); | |
var advancedResolve = new Futures(function (resolve, reject) { | |
return new Promise(function (resolve1, reject2) { | |
resolve('test'); | |
}); | |
}) | |
.then( | |
function (resolveValue) { | |
console.log('piped.resolved', resolveValue === 'test'); | |
return 'test2'; | |
}, | |
function (rejectValue) { | |
console.log('piped.rejected', 'failed'); | |
} | |
) | |
.then( | |
function (resolveValue) { | |
console.log('advancedResolve.piped.resolved', resolveValue === 'test2'); | |
}, | |
function (rejectValue) { | |
console.log('advancedResolve.piped.rejected', 'failed'); | |
} | |
); | |
var advancedReject = new Futures(function (resolve, reject) { | |
return new Promise(function (resolve1, reject2) { | |
reject('test'); | |
}); | |
}) | |
.then( | |
function (resolveValue) { | |
console.log('advancedReject.piped.resolved', 'failed'); | |
}, | |
function (rejectValue) { | |
console.log('advancedReject.piped.rejected', rejectValue === 'test'); | |
return 'test2'; | |
} | |
) | |
.then( | |
function (resolveValue) { | |
console.log('advancedReject.piped.resolved', 'failed'); | |
}, | |
function (rejectValue) { | |
console.log('advancedReject.piped.rejected', 'failed'); | |
} | |
); | |
}, 400) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment