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
  • Select an option

  • Save qetr1ck-op/00e20af1ffee43a1bfc34c6b4a059bf5 to your computer and use it in GitHub Desktop.

Select an option

Save qetr1ck-op/00e20af1ffee43a1bfc34c6b4a059bf5 to your computer and use it in GitHub Desktop.

Revisions

  1. qetr1ck-op revised this gist Jul 16, 2018. 2 changed files with 157 additions and 147 deletions.
    157 changes: 157 additions & 0 deletions custom-promise.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,157 @@
    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();
    147 changes: 0 additions & 147 deletions rastas-promise.js
    Original file line number Diff line number Diff line change
    @@ -1,147 +0,0 @@
    const PENDING = 1
    const RESOLVED = 2
    const REJECTED = 3

    const callLater = (fn) => setTimeout(fn, 0)

    class Promise {
    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 Promise((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 Promise((resolve) => resolve(value))
    }

    static reject(value) {
    return new Promise((resolve, reject) => reject(value))
    }

    static delay(ms, value) {
    return new Promise((resolve) => setTimeout(() => resolve(value), ms))
    }

    static fromNode(fn) {
    return new Promise((resolve, reject) => {
    const resolveNode = (err, res) => {
    if (err) return reject(err)
    resolve(res)
    }
    fn(resolveNode)
    })
    }

    static promisify(nodeFn) {
    return (...args) => Promise.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`] = Promise.promisify(module[key]))
    return module
    }

    static all(promises) {
    return new Promise((resolve, reject) => {
    const values = new Array(promises.length)
    let counter = 0
    const tryResolve = (i) => (value) => {
    values[i] = value
    counter++
    if (counter === promises.length) {
    resolve(values)
    }
    }
    for (let i = 0; i < promises.length; i++) {
    const promise = promises[i]
    promise.then(tryResolve(i), reject)
    }
    })
    }
    }
  2. @ronkot ronkot revised this gist Mar 27, 2018. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions rastas-promise.js
    Original file line number Diff line number Diff line change
    @@ -2,9 +2,7 @@ const PENDING = 1
    const RESOLVED = 2
    const REJECTED = 3

    const callLater = setImmediate
    ? setImmediate // efficient in Node
    : (fn) => setTimeout(fn, 0) // only choice in browsers
    const callLater = (fn) => setTimeout(fn, 0)

    class Promise {
    constructor(fn) {
  3. @ronkot ronkot revised this gist Nov 13, 2017. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions rastas-promise.js
    Original file line number Diff line number Diff line change
    @@ -146,6 +146,4 @@ class Promise {
    }
    })
    }
    }

    module.exports = Promise
    }
  4. @ronkot ronkot revised this gist Nov 13, 2017. 1 changed file with 23 additions and 19 deletions.
    42 changes: 23 additions & 19 deletions rastas-promise.js
    Original file line number Diff line number Diff line change
    @@ -8,44 +8,48 @@ const callLater = setImmediate

    class Promise {
    constructor(fn) {
    this.state = PENDING
    this.value = undefined
    this.thenners = []
    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())
    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())
    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))
    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)
    this._thenners.push(thenner)
    }
    }

    /* Public methods */

    then(onResolved, onRejected) {
    return new Promise((resolve, reject) => {
    const thenner = {
    @@ -90,7 +94,7 @@ class Promise {
    return this.then(undefined, onRejected)
    }

    /* Static helpers */
    /* Public static tools */

    static resolve(value) {
    return new Promise((resolve) => resolve(value))
  5. @ronkot ronkot revised this gist Nov 13, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion rastas-promise.js
    Original file line number Diff line number Diff line change
    @@ -100,7 +100,7 @@ class Promise {
    return new Promise((resolve, reject) => reject(value))
    }

    static delay(value, ms) {
    static delay(ms, value) {
    return new Promise((resolve) => setTimeout(() => resolve(value), ms))
    }

  6. @ronkot ronkot revised this gist Nov 13, 2017. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions rastas-promise.js
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,10 @@ const PENDING = 1
    const RESOLVED = 2
    const REJECTED = 3

    const callLater = setImmediate
    ? setImmediate // efficient in Node
    : (fn) => setTimeout(fn, 0) // only choice in browsers

    class Promise {
    constructor(fn) {
    this.state = PENDING
    @@ -34,9 +38,9 @@ class Promise {

    _handleThenner(thenner) {
    if (this.state === RESOLVED) {
    thenner.onResolved && setImmediate(() => thenner.onResolved(this.value))
    thenner.onResolved && callLater(() => thenner.onResolved(this.value))
    } else if (this.state === REJECTED) {
    thenner.onRejected && setImmediate(() => thenner.onRejected(this.value))
    thenner.onRejected && callLater(() => thenner.onRejected(this.value))
    } else {
    this.thenners.push(thenner)
    }
    @@ -79,7 +83,7 @@ class Promise {
    }

    done(onResolved) {
    this.then(onResolved)
    return this.then(onResolved)
    }

    catch(onRejected) {
  7. @ronkot ronkot created this gist Nov 13, 2017.
    143 changes: 143 additions & 0 deletions rastas-promise.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,143 @@
    const PENDING = 1
    const RESOLVED = 2
    const REJECTED = 3

    class Promise {
    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)
    }

    _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 && setImmediate(() => thenner.onResolved(this.value))
    } else if (this.state === REJECTED) {
    thenner.onRejected && setImmediate(() => thenner.onRejected(this.value))
    } else {
    this.thenners.push(thenner)
    }
    }

    then(onResolved, onRejected) {
    return new Promise((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) {
    this.then(onResolved)
    }

    catch(onRejected) {
    return this.then(undefined, onRejected)
    }

    /* Static helpers */

    static resolve(value) {
    return new Promise((resolve) => resolve(value))
    }

    static reject(value) {
    return new Promise((resolve, reject) => reject(value))
    }

    static delay(value, ms) {
    return new Promise((resolve) => setTimeout(() => resolve(value), ms))
    }

    static fromNode(fn) {
    return new Promise((resolve, reject) => {
    const resolveNode = (err, res) => {
    if (err) return reject(err)
    resolve(res)
    }
    fn(resolveNode)
    })
    }

    static promisify(nodeFn) {
    return (...args) => Promise.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`] = Promise.promisify(module[key]))
    return module
    }

    static all(promises) {
    return new Promise((resolve, reject) => {
    const values = new Array(promises.length)
    let counter = 0
    const tryResolve = (i) => (value) => {
    values[i] = value
    counter++
    if (counter === promises.length) {
    resolve(values)
    }
    }
    for (let i = 0; i < promises.length; i++) {
    const promise = promises[i]
    promise.then(tryResolve(i), reject)
    }
    })
    }
    }

    module.exports = Promise