if I call this function, it doesn't seem to work. what it's doing is just waiting for global variable "window.AppApi" to be initialized before doing things
i feel like maybe it's because i'm calling the function again in the time out? is there something I'm missing to make this work? if it's not possible what would be a good alternative..
initializeApp()
.then(( result ) => {
console.log( 'it worked!' ); // does not go here
});
export const initializeApp = () => {
return new Promise(( resolve, reject ) => {
// wait for App API to be initialized
if ( window.AppApi ) {
console.log( 'App initialized.' );
resolve( true );
}
else {
console.log( 'waiting for App to initialize...' );
setTimeout( () => initializeApp(), 250 );
}
});
};
Technically you can do it even without dirty timeouts with old good Object.defineProperty setter:
const initializeApp = () => { return new Promise((resolve, reject) => { if (window.AppApi) { resolve(true); return; } Object.defineProperty(window, 'AppApi', { set (value) { console.log('App initialized.'); resolve(true); return value } }) }); }; initializeApp() .then((result) => { console.log('it worked!'); // does not go here }); setTimeout(() => { window.AppApi = { test: 123 } }, 2000)
The problem is that the setTimeout( () => initializeApp(), 250 )
will create a new Promise that is not used anywhere, and the first Promise that is created - and which is the only relevant for your first code block - will only be resolve if window.AppApi
is set before the first call of initializeApp
.
You would have to write somethign like this:
export const initializeApp = () => {
return new Promise((resolve, reject) => {
// an "inner" function that creates a closure over resolve
// and which does the check if window.AppApi is set
function checkIfApiLoaded() {
if (window.AppApi) {
console.log('App initialized.');
resolve(true);
} else {
console.log('waiting for App to initialize...');
// if window.AppApi was not set call checkIfApiLoaded with a delay,
// because of the closure it will still know the 'resolve' function
setTimeout(checkIfApiLoaded, 250);
}
}
// initially call this inner function
checkIfApiLoaded()
});
Instead of polling for this value, you could define it as a getter that resolves the promise:
const initializeApp = () => new Promise(resolve => { const { AppApi } = window; if (AppApi) return resolve(AppApi); Object.defineProperty(window, 'AppApi', { get () { return AppApi; }, set (value) { console.log('App initialized.'); Object.defineProperty(window, 'AppApi', { value, enumerable: true, configurable: true, writable: true }); resolve(value); }, enumerable: true, configurable: true }); }); initializeApp().then(AppApi => { console.log(AppApi); }); setTimeout(() => window.AppApi = { test: 123 }, 1000);
This uses Object.defineProperty()
to create a property accessor that resolves the promise immediately when the API is flagged as ready. This also has the added benefit of resolving with the value of AppApi
so if it's a namespace you'll have it available as the first argument of the callback function for .then()
.
I think the issue is that your initializeApp
function creates a new promise each time it's called. So when it's called recursively, the original promise is lost and will never resolve. Instead, put the recursive part into its own sub-function, and call that recursively:
const initializeApp = () => { const resolver = (res) => { if (window.AppApi) { res(true); } else { setTimeout(resolver, 250, res); } } return new Promise(( resolve, reject ) => { resolver(resolve) }); }; initializeApp().then(( result ) => { console.log( 'it worked!' ); }); setTimeout(() => { console.log("Setting api"); window.AppApi = {} }, 2000);
Since window.AppApi
is a value that is available in the future you may think of an object that represents that.....
A promise.
If window.AppApi
is set to promise of AppApi
then when you want to use it you can do:
window.AppApi.then(...
But in order to do that you should not show initializeApp
but the code that set AppApi and how you do that. Because it seems that initializeApp
solves a problem (quite elegantly in some answers) that should not exist in the first place.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.