Search code examples
javascriptfetch-apies6-promise

Calling an optional JS fetch promise from multiple code locations


I have three URLs I need to access in my code. The first two will always be accessed, but the third one might be accessed zero, one or two times. As all URLs take a lot of processing, I don't want to access the third one if I don't have to.

My code is something like this:

fetch('a')
.then(response => response.json() }
.then(data => {
  if (data.value == '1') {
    fetch('c')
    .then(response => response.json() }
    .then(data => console.log('through a', data));
  }
}
fetch('b')
.then(response => response.json() }
.then(data => {
  if (data.value == '1') {
    fetch('c')
    .then(response => response.json() }
    .then(data => console.log('through a', data));
  }
}

So, the result from URL 'c' might be needed zero, one or two times. Both a, b and c can take a while to process, so either 'a' or 'b' might be first accessing 'c'. In case both need to return 'c', I don't want a second fetch to be performed, I want the second one to return the value already fetched by the first one.

My thought was to do it like this:

const c = () => {
  return new Promise(() => {
    fetch('c')
    .then(response => response.json() };
  })
}

fetch('a')
.then(response => response.json() }
.then(data => {
  if (data.value == '1') {
    c().then(data => console.log('through a', data));
  }
}
fetch('b')
.then(response => response.json() }
.then(data => {
  if (data.value == '1') {
    c().then(data => console.log('through b', data));
  }
}

But this still causes 'c' to be accessed twice if both 'a' and 'b' return '1'.

How should I do this instead?


Solution

  • Sounds like you want to lazily call "c" and at most once.

    Something like this should suffice

    let cPromise;
    
    const c = () => (cPromise ??= fetch("c").then((r) => r.json()));
    
    fetch("a")
      .then((r) => r.json())
      .then(({ value }) => {
        if (value === "1") {
          c().then((data) => {
            console.log("through a", data);
          });
        }
      });
    
    fetch("b")
      .then((r) => r.json())
      .then(({ value }) => {
        if (value === "1") {
          c().then((data) => {
            console.log("through a", data);
          });
        }
      });
    

    The Nullish coalescing assignment (??=) means cPromise will only be assigned once when c() is first called. It also means fetch("c") will only be called at most one time.