Last active
October 22, 2021 18:22
-
-
Save snewcomer/4ee2d7092742be8666343dbe0e56c1ee to your computer and use it in GitHub Desktop.
await non model hook promise ember
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
import Helper from '@ember/component/helper'; | |
import { inject as service } from '@ember/service'; | |
import { assert } from '@ember/debug'; | |
import { tracked } from '@glimmer/tracking'; | |
class AsyncData { | |
constructor(list) { | |
if (list) { | |
this._value = []; | |
} | |
} | |
/** | |
@type {'LOADING' | 'LOADED' | 'ERROR'} | |
@private | |
*/ | |
@tracked _state = 'LOADING'; | |
/** @private */ | |
@tracked _value; | |
/** @private */ | |
@tracked _error; | |
get state() { | |
return this._state; | |
} | |
get value() { | |
return this._value; | |
} | |
get error() { | |
assert(`You can only access 'error' when 'state' is 'ERROR', but it is ${this.state}`, this.state === 'ERROR'); | |
return this._error; | |
} | |
get isLoading() { | |
return this.state === 'LOADING'; | |
} | |
get isLoaded() { | |
return this.state === 'LOADED'; | |
} | |
get isError() { | |
return this.state === 'ERROR'; | |
} | |
resolveWith(value) { | |
this._state = 'LOADED'; | |
// TODO: we need a macrotask here when *library gives us back a Promise that won't hit network. | |
// without, it will starve rendering and won't paint the header text (Browse) until all content is painted | |
this._value = value; | |
} | |
rejectWith(error) { | |
this._state = 'ERROR'; | |
this._error = error; | |
} | |
} | |
class ResolvedData { | |
state = 'LOADED'; | |
isLoading = false; | |
isLoaded = true; | |
isError = false; | |
constructor(data) { | |
this._value = data; | |
} | |
get value() { | |
return this._value; | |
} | |
} | |
const OUTSTANDING_PROMISES = new WeakMap(); | |
export default class Await extends Helper { | |
@service router; | |
/** | |
* @method compute | |
* @public | |
* @param params Array a list of arguments passed to the Helper. | |
* @param hash Object a list of configuration options passed to the helper. | |
* @param hash.list We can render an empty list while the promise is outstanding, preventing errors downstream | |
*/ | |
compute([maybePromise], { list = false }) { | |
const existingAsyncData = OUTSTANDING_PROMISES.get(maybePromise); | |
if (existingAsyncData) { | |
return existingAsyncData; | |
} | |
// this may be a resolved data structure from the model hook if we block there | |
if (!maybePromise || typeof maybePromise.then !== 'function') { | |
return new ResolvedData(maybePromise); | |
} | |
const asyncData = new AsyncData(list, this.router); | |
OUTSTANDING_PROMISES.set(maybePromise, asyncData); | |
maybePromise.then( | |
(value) => asyncData.resolveWith(value), | |
(error) => { | |
asyncData.rejectWith(error); | |
if (!this.router._router.outstandingTransitions.length) { | |
this.router.transitionTo('error'); | |
} | |
} | |
); | |
return asyncData; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment