Skip to content

Instantly share code, notes, and snippets.

@qetr1ck-op
Forked from ronkot/rastas-promise.js
Last active July 16, 2018 20:08
Show Gist options
  • Save qetr1ck-op/00e20af1ffee43a1bfc34c6b4a059bf5 to your computer and use it in GitHub Desktop.
Save qetr1ck-op/00e20af1ffee43a1bfc34c6b4a059bf5 to your computer and use it in GitHub Desktop.
Simple Promise implementation
const PENDING = 1;
const RESOLVED = 2;
const REJECTED = 3;
const callLater = fn => setTimeout(fn, 0);
class MyPromise {
constructor(fn) {
this._state = PENDING;
this._value = undefined;
this._thenners = [];
this._resolve = this._resolve.bind(this);
this._reject = this._reject.bind(this);
fn(this._resolve, this._reject);
}
/* Helper methods */
_resolve(value) {
if (this._state === PENDING) {
this._state = RESOLVED;
this._value = value;
while (this._thenners.length > 0) {
this._handleThenner(this._thenners.pop());
}
}
}
_reject(value) {
if (this._state === PENDING) {
this._state = REJECTED;
this._value = value;
while (this._thenners.length > 0) {
this._handleThenner(this._thenners.pop());
}
}
}
_handleThenner(thenner) {
if (this._state === RESOLVED) {
thenner.onResolved && callLater(() => thenner.onResolved(this._value));
} else if (this._state === REJECTED) {
thenner.onRejected && callLater(() => thenner.onRejected(this._value));
} else {
this._thenners.push(thenner);
}
}
/* Public methods */
then(onResolved, onRejected) {
return new MyPromise((resolve, reject) => {
const thenner = {
onResolved: value => {
let nextValue = value;
if (onResolved) {
try {
nextValue = onResolved(value);
if (nextValue && nextValue.then) {
return nextValue.then(resolve, reject);
}
} catch (err) {
return reject(err);
}
}
resolve(nextValue);
},
onRejected: value => {
let nextValue = value;
if (onRejected) {
try {
nextValue = onRejected(value);
if (nextValue && nextValue.then) {
return nextValue.then(resolve, reject);
}
} catch (err) {
return reject(err);
}
}
resolve(nextValue);
}
};
this._handleThenner(thenner);
});
}
done(onResolved) {
return this.then(onResolved);
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
/* Public static tools */
static resolve(value) {
return new MyPromise(resolve => resolve(value));
}
static reject(value) {
return new MyPromise((resolve, reject) => reject(value));
}
static delay(ms, value) {
return new MyPromise(resolve => setTimeout(() => resolve(value), ms));
}
static fromNode(fn) {
return new MyPromise((resolve, reject) => {
const resolveNode = (err, res) => {
if (err) return reject(err);
resolve(res);
};
fn(resolveNode);
});
}
static promisify(nodeFn) {
return (...args) => MyPromise.fromNode(resolveFn => nodeFn(...args, resolveFn));
}
static promisifyAll(module) {
Object.keys(module)
.filter(key => typeof module[key] === 'function' && !key.endsWith('Sync'))
.forEach(key => (module[`${key}Async`] = MyPromise.promisify(module[key])));
return module;
}
static all(Mypromises) {
return new MyPromise((resolve, reject) => {
const values = new Array(Mypromises.length);
let counter = 0;
const tryResolve = i => value => {
values[i] = value;
counter++;
if (counter === Mypromises.length) {
resolve(values);
}
};
for (let i = 0; i < Mypromises.length; i++) {
const Mypromise = Mypromises[i];
Mypromise.then(tryResolve(i), reject);
}
});
}
}
const main = async arguments => {
const p = await new MyPromise(resolve => {
setTimeout(() => {
resolve('data');
}, 100);
});
console.log(p);
};
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment