1

I have the following code

import fetch, { Response } from "node-fetch"
import { joinCookieNameAndValue } from "../string-manipulation"
import item from "../../types/data-types/item"

const scan = (name: string, page: number): Promise<item | void> => new Promise(async (resolve, reject) => {
    const itemsRes: Response = await fetch(`url`, {
        method: "GET",
        headers: {
            Cookie: joinCookieNameAndValue("cookie-name", <string> process.env.COOKIE_VALUE)
        }
    })

    if (!itemsRes.ok) {
        return reject(new Error(`Could not fetch items: request failed with status code ${itemsRes.status}`));
    }

    const items: Array<item> = await itemsRes.json();
    const item_: item | undefined = items.find(i => i.name == name);

    if (items.length == 0) {
        return resolve();
    }

    if (!item_) {
        return scan(name, ++page);
    }

    resolve(item);
})

export default async (name: string) => scan(name, 1);

The promise above is awaited in another script but the code after it won't ever run as the promise never gets resolved even though the code inside the items.length == 0 if statement runs.

code_monk
  • 9,451
  • 2
  • 42
  • 41
iKingNinja
  • 113
  • 9
  • 1
    In the case `if (!item)` you never resolve the promise. But taking a step back, you shouldn't be applying the [promise constructor anti-pattern](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it). – trincot Jun 08 '23 at 21:00
  • @trincot does that mean that by calling `scan(name, ++page)` I'm creating new promises that will never be resolvled and that's why the code calling the function gets stuck? – iKingNinja Jun 08 '23 at 21:11
  • 1
    @iKingNinja that means you should just `const scan = async (name: string, page: number): Promise => { ...; return item; }` – Dimava Jun 08 '23 at 23:09
  • 1
    [Never pass an `async function` as the executor to `new Promise`](https://stackoverflow.com/q/43036229/1048572)! – Bergi Jun 09 '23 at 02:05

1 Answers1

2

There's a number of strange things going on in your code, but the key issue is indeed that in the second exit of your function, you immediately return and the promise (created with the initial new Promise()) will never resolve.

Also, once a promise has been resolved, it can never be resolved again. Once it transitions from the pending to a resolved/rejected state, that state (and the accompanying value) is permanent.

The best way to solve this though, is to get rid of what's considered a bad thing anyway, don't use new Promise with async/await.

Here's a rewritten version of the code you shared:

async function scan(name: string, page: number): PromiseLike<item | null> {
  const itemsRes: Response = await fetch(`url`, {
    method: "GET",
    headers: {
      Cookie: joinCookieNameAndValue("cookie-name", <string> process.env.COOKIE_VALUE)
    }
  })

  if (!itemsRes.ok) {
    throw new Error(`Could not fetch items: request failed with status code ${itemsRes.status}`);
  }

  const items: Array<item> = await itemsRes.json();
  const item_: item | undefined = items.find(i => i.name == name);

  if (items.length == 0) {
    return null;
  }

  if (!item_) {
    return scan(name, page+1);
  }

  return item;
}

export default (name: string) => scan(name, 1);
Evert
  • 93,428
  • 18
  • 118
  • 189