繁体   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