簡體   English   中英

解決一個調用自己函數的Promise

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM