'Variable is magically turning into undefined through stack

Here are the relevant parts of my code. Notice the console.log statements.

async function matchChannel(
  context: coda.ExecutionContext,
  channelLabel: string
) {
  ...

  console.log(`allTeamIds = ${JSON.stringify(allTeamIds)}`);
  try {
    // promiseAny is a back-ported shim for Promise.any https://www.npmjs.com/package/promise.any
    return await promiseAny(
      allTeamIds.map(async (teamId) => {
        // Get channels with either id or displayName as channelLabel
        console.log(`teamId = ${teamId}`);
        const channels = (await listChannels(context, teamId)).body.value;
        console.log(`teamId (after) = ${teamId}`);
        ...
      })
    );
  } catch (error: any) {
    ...
  }
}

export async function listChannels(
  context: coda.ExecutionContext,
  teamId: string,
  ids?: string[],
  displayNames?: string[]
) {
  console.log(`listChannels(teamId = ${teamId})`);
  return await tryDumpFetchParams<ListChannelsResponseBody>(context, {
    url: channelsUrl(teamId, ids, displayNames),
    method: Method.Get,
    headers: jsonApplicationHeader,
  });
}

export function channelsUrl(
  teamId: string,
  ids?: string[],
  displayNames?: string[]
) {
  function emptyArrayIfUndefined(arr?: Array<any>) {
    return arr ?? [];
  }

  console.log(`channelsUrl(teamId = ${teamId})`);
  ...
}

I'm getting the following:

allTeamIds = ["ee5e8e7a-ff63-4a6b-89e1-6b28be218ca3","1bd14e82-544f-4a4c-98c5-4c837596e8ae"]
teamId = ee5e8e7a-ff63-4a6b-89e1-6b28be218ca3
listChannels(teamId = ee5e8e7a-ff63-4a6b-89e1-6b28be218ca3)
channelsUrl(teamId = ee5e8e7a-ff63-4a6b-89e1-6b28be218ca3)
teamId = 1bd14e82-544f-4a4c-98c5-4c837596e8ae
listChannels(teamId = 1bd14e82-544f-4a4c-98c5-4c837596e8ae)
teamId (after) = 1bd14e82-544f-4a4c-98c5-4c837596e8ae
channelsUrl(teamId = undefined) <-- WTH
teamId (after) = ee5e8e7a-ff63-4a6b-89e1-6b28be218ca3

Why is teamId magically turning into undefined?! It's not like this is some closure that gets overwritten. Am I crazy or is this unexpected behavior?



Solution 1:[1]

Sorry, this was my mistake. Although I was getting an error, it was unrelated. I was actually returning successfully from matchChannel.

I'm pretty sure the undefined is due to a release of memory after the first promise resolved. It looks like the promiseAny was doing its job.

Edit:

Sorry for not seeing the comments earlier. I'll elaborate.

promiseAny is just going to evaluate to the first promise that resolves.

    return await promiseAny(
      allTeamIds.map(async (teamId) => {
        ...
      })
    );

When the successful promise resolves, the other promises aren't necessary anymore, so node is going to start cleaning up all of the memory involved in the other promises.

Note that teamId is an element in the array resulting from allTeamIds.map(...). If I were to delete an element inside an array, I'd see undefined as well.

const array = [1, 2];
delete array[0];
// prints 'undefined'
console.log(array[0]);

I guess this cleanup happens in a clumsy way where my print statements get executed after the memory cleanup. The event loop may just have kept on churning while the memory had already gotten cleaned up.

Unfortunately, my ability to reproduce was limited by the fact that I was uploading the code to remote servers with a custom sandboxed runtime.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1