[英]Resolving a Promise that calls own function
如果我调用此函数,它似乎不起作用。 它所做的只是在执行操作之前等待全局变量“ window.AppApi”被初始化
我觉得可能是因为我在超时时间内再次调用了该函数? 有什么我需要使这项工作吗? 如果不可能的话,那将是一个很好的选择。
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 );
}
});
};
从技术上讲,即使使用旧的良好的Object.defineProperty设置器,也可以避免超时超时:
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)
问题在于setTimeout( () => initializeApp(), 250 )
将创建一个新的Promise,该Promise不会在任何地方使用,并且创建的第一个Promise-与您的第一个代码块唯一相关-仅会如果在第一次调用initializeApp
之前设置了window.AppApi
解决。
您将必须编写如下内容:
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()
});
您可以将其定义为解决承诺的getter,而不用轮询该值:
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);
它使用Object.defineProperty()
创建属性访问器,当API被标记为就绪时,该访问器立即解析promise。 这也具有使用AppApi
的值进行解析的附加好处,因此,如果它是名称空间,则可以将其用作.then()
的回调函数的第一个参数。
我认为问题在于您的initializeApp
函数每次调用都会创建一个新的Promise。 因此,当递归调用它时,原始的承诺将丢失并且永远无法解决。 而是将递归部分放入其自己的子函数中,然后递归调用:
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);
由于window.AppApi
是将来可用的值,因此您可能会想到一个表示该值的对象。
一个承诺。
如果window.AppApi
设置承诺的AppApi
那么当你想使用它,你可以这样做:
window.AppApi.then(...
但是为了做到这一点,您不应该显示initializeApp
而是显示设置AppApi的代码以及如何执行此操作。 因为似乎initializeApp
解决了最初不应该存在的问题(在某些答案中很优雅)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.