[英]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.