简体   繁体   English

解决一个调用自己函数的Promise

[英]Resolving a Promise that calls own function

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 它所做的只是在执行操作之前等待全局变量“ window.AppApi”被初始化

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: 从技术上讲,即使使用旧的良好的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) 

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 . 问题在于setTimeout( () => initializeApp(), 250 )将创建一个新的Promise,该Promise不会在任何地方使用,并且创建的第一个Promise-与您的第一个代码块唯一相关-仅会如果在第一次调用initializeApp之前设置了window.AppApi解决。

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: 您可以将其定义为解决承诺的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); 

This uses Object.defineProperty() to create a property accessor that resolves the promise immediately when the API is flagged as ready. 它使用Object.defineProperty()创建属性访问器,当API被标记为就绪时,该访问器立即解析promise。 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() . 这也具有使用AppApi的值进行解析的附加好处,因此,如果它是名称空间,则可以将其用作.then()的回调函数的第一个参数。

I think the issue is that your initializeApp function creates a new promise each time it's called. 我认为问题在于您的initializeApp函数每次调用都会创建一个新的Promise。 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..... 由于window.AppApi是将来可用的值,因此您可能会想到一个表示该值的对象。

A promise. 一个承诺。

If window.AppApi is set to promise of AppApi then when you want to use it you can do: 如果window.AppApi设置承诺的AppApi那么当你想使用它,你可以这样做:

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. 但是为了做到这一点,您不应该显示initializeApp而是显示设置AppApi的代码以及如何执行此操作。 Because it seems that initializeApp solves a problem (quite elegantly in some answers) that should not exist in the first place. 因为似乎initializeApp解决了最初不应该存在的问题(在某些答案中很优雅)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM