Skip to content

Instantly share code, notes, and snippets.

@kerbyfc
Created January 20, 2018 11:35
Show Gist options
  • Save kerbyfc/9da1f2bf32d527b65215e4b596bc1256 to your computer and use it in GitHub Desktop.
Save kerbyfc/9da1f2bf32d527b65215e4b596bc1256 to your computer and use it in GitHub Desktop.
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