Last active
October 4, 2017 15:42
-
-
Save sergeysova/1a5105cb1823c51511a5bda7c25aac5f 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
| const isThenable = p => | |
| p && typeof p.then === 'function' | |
| const isPromisable = p => | |
| isThenable(p) && typeof p.catch === 'function' | |
| class Prom { | |
| /** | |
| * | |
| * @param {(resolve: (data) => void, reject: (error) => void) => void} fn | |
| */ | |
| constructor(fn) { | |
| this._resolvedChain = [] | |
| this._rejectedChain = [] | |
| this._status = 0 // 0 — pending, 1 — resolved, 2 — rejected | |
| this._lastResult = undefined | |
| this._lastError = undefined | |
| const resolver = (data) => { | |
| // console.log('resolver()', this._status, data) | |
| if (!this._isPending) return | |
| if (isThenable(data)) { | |
| data.then(result => { | |
| this._status = 1 | |
| this._lastResult = result | |
| this._resolvedChain.forEach(resolve => resolve(result)) | |
| }) | |
| } | |
| else { | |
| this._status = 1 | |
| this._lastResult = data | |
| this._resolvedChain.forEach(resolve => resolve(data)) | |
| } | |
| } | |
| const rejector = (error) => { | |
| // console.log('rejector()', this._status, error, this._rejectedChain.length) | |
| if (!this._isPending) return | |
| this._status = 2 | |
| this._lastError = error | |
| this._rejectedChain.forEach(reject => reject(error)) | |
| if (!this._rejectedChain.length) { | |
| throw new Error(this._lastError) | |
| } | |
| } | |
| fn(resolver, rejector) | |
| } | |
| get _isPending() { | |
| return this._status === 0 | |
| } | |
| get _isResolved() { | |
| return this._status === 1 | |
| } | |
| get _isRejected() { | |
| return this._status === 2 | |
| } | |
| _invoke() { | |
| setTimeout(() => { | |
| if (this._isResolved) { | |
| this._resolvedChain.forEach(fn => fn(this._lastResult)) | |
| } | |
| else if (this._isRejected) { | |
| this._rejectedChain.forEach(fn => fn(this._lastError)) | |
| } | |
| }, 0) | |
| } | |
| then(handler, catcher) { | |
| return new Prom((resolve, reject) => { | |
| if (catcher) { | |
| this._rejectedChain.push(data => { | |
| try { | |
| const result = catcher(data) | |
| if (isPromisable(result)) { | |
| result.then(resolve).catch(reject) | |
| } else { | |
| resolve(result) | |
| } | |
| } catch (error) { | |
| reject(error) | |
| } | |
| }) | |
| } | |
| else { | |
| this._rejectedChain.push(reject) | |
| } | |
| this._resolvedChain.push(data => { | |
| try { | |
| const result = handler(data) | |
| if (isPromisable(result)) { | |
| result.then(resolve).catch(reject) | |
| } | |
| else { | |
| resolve(result) | |
| } | |
| } | |
| catch (error) { | |
| reject(error) | |
| } | |
| }) | |
| this._invoke() | |
| }) | |
| } | |
| /** | |
| * @param {Function} catcher | |
| * @return {Prom} | |
| */ | |
| catch(catcher) { | |
| return new Prom((resolve, reject) => { | |
| this._resolvedChain.push(resolve) | |
| this._rejectedChain.push(data => { | |
| try { | |
| const result = catcher(data) | |
| if (isPromisable(result)) { | |
| result.then(resolve).catch(reject) | |
| } | |
| else { | |
| resolve(result) | |
| } | |
| } | |
| catch (error) { | |
| reject(error) | |
| } | |
| }) | |
| this._invoke() | |
| }) | |
| } | |
| static resolve(data) { | |
| const inst = new Prom(() => {}) | |
| inst._status = 1 | |
| inst._lastResult = data | |
| return inst | |
| } | |
| static reject(error) { | |
| const inst = new Prom(() => {}) | |
| inst._status = 2 | |
| inst._lastError = error | |
| return inst | |
| } | |
| } |
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
| const wait = (ms) => new Prom(resolve => { | |
| setTimeout(() => resolve(ms), ms) | |
| }) | |
| const start = new Prom((resolve, reject) => { | |
| resolve(new Prom(resolve => resolve(10)).then(e => wait(100))) | |
| }) | |
| start.then(data => { | |
| console.log('resolved', data) | |
| return 1000 | |
| }).then(console.log) | |
| Prom.reject(100) | |
| .catch(err => { | |
| console.error('Catched error', { err }) | |
| }) |
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
| const wait = (ms) => new Prom(resolve => { | |
| setTimeout(() => resolve(ms), ms) | |
| }) | |
| wait(100) | |
| .catch(err => { | |
| throw new TypeError('Dooom') | |
| }) | |
| .then(data => (console.log('resolved', { data }), 12)) | |
| .then(twelve => console.log('12', { twelve })) | |
| .then(undef => { | |
| throw new Error('argh') | |
| }) | |
| .catch(foo => { | |
| console.log({ foo: foo.message }) | |
| return 900 | |
| }) | |
| .then(nine => console.log({ nine })) |
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
| const wait = (ms) => new Prom(resolve => { | |
| setTimeout(() => resolve(ms), ms) | |
| }) | |
| wait(100) | |
| .then(first => { | |
| console.log({ first }) | |
| return wait(50).then(second => { | |
| console.log({ second }) | |
| throw 900 | |
| }) | |
| }) | |
| .catch(third => { | |
| console.log({ third }) | |
| throw 450 | |
| }) | |
| .then(skip => console.log({ skip })) // Should be skipped | |
| .catch(four => { | |
| console.log({ four }) | |
| return Prom.resolve(300) | |
| }) | |
| .then(fivth => { | |
| console.log({ fivth }) | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment