2

I have an Angular app that opens a link to an external site in a new tab when I click a button and then checks in an interval, if the tab is closed and when it is closed do stuff.

This works sometimes, but sometimes this doesn't work and the app gets stuck and doesn't respond anymore. Not even a refresh works and I have to close the tab of the app and open the app again in a new tab.

The first time the code runs and opens a tab, this issue (almost) never appears, only if the tab was closed and opened again with another click on the button (even then the issue appeared only like half the time). Sometimes this happens on the second click, sometimes on the 7th or any other number of times.

I refactored the code down to the following version with setInterval:

async foo() {
    this.someWindow = window.open('https://google.at', '_blank');
    const id = setInterval(() => {
        if (this.someWindow.closed) {
            clearInterval(id);
            console.log('finished');
        }
    }, 2000);
}

and this version with setTimeout

async foo() {
    const fn = async () => {
        if (this.someWindow.closed) {
            console.log('finished');
        } else {
            setTimeout(fn, 1000);
        }
    };
    this.someWindow = window.open('https://google.at', '_blank');
    setTimeout(fn, 1000);
}

There is definitely something wrong with the async and it gets stuck in an infinite loop or something like that, but I don't know what's the problem or if there is an alternative to this. I need the method to be async though, because I make an http request to get the correct url to open.

mKay
  • 301
  • 1
  • 3
  • 15
  • Instead of relying on the `setTimeout`, use the callback when window is closed, See this [answer](https://stackoverflow.com/a/13151777/11719787), Not tried but might help – Sameer Jun 23 '22 at 14:58
  • what you have written doesn't make sense to me. why would you set a timeout delay which does nothing more than set another timeout delay? And why add async to a function that is called with setTimeout? Isn't that redundant? – Rick Jun 23 '22 at 15:25
  • I have to take a look at callback. But it seems that this does not work, if the child site is an external site where I can't change the code. – mKay Jun 24 '22 at 08:00
  • And yes, there was a mistake in the timeout version. I fixed it now. It just calls itself recursively to check if the tab was closed and if it was closed, finish. Just like the setInterval version. – mKay Jun 24 '22 at 08:01

2 Answers2

0

You need to do it recursively.

let someWindow = window.open('https://google.at', '_blank');
function myFunction(){
    if (someWindow.closed){
        console.log('finished');
    }else{
        setTimeout(() => {
            myFunction();
        }, 2000);
    }
}
Ghaith Troudi
  • 248
  • 1
  • 8
  • There was a mistake in the setTimeout version of the code and I fixed it in the original question. I do it recursively. – mKay Jun 24 '22 at 07:58
  • Your approach is checking for `someWindow.closed` only once, so it's going to log `finished` every `3s` even if the window is not closed yet, try to make these changes `const fn = async () => {setTimeout(() =>foo(), 2000);};` and `else {fn();}` – Ghaith Troudi Jun 24 '22 at 08:27
0

This will get caught in an infinite loop if the tab is blocked by a pop-up blocker. In that case window.open will return null. So make sure you check for that.

  async foo() {
    const someWindow = window.open('https://google.at', '_blank');
    if (!someWindow) window.alert('Tab Blocked!');
    else {
      const id = setInterval(() => {
        if (someWindow.closed) {
          clearInterval(id);
          console.log('finished');
        }
      }, 2000);
    }
  }
Chris Hamilton
  • 9,252
  • 1
  • 9
  • 26