0

Below is a minimized code snippet which causes the async warning in VS code (most recent version 1.70.). It is part of a load balancing algorithm which is to execute asynchronous tasks.

When the generateTask function returns a promise directly the warning disappears. When the Promise.all promise is returned I get the warning "await has no effect" (w1). Despite the warning the code behaves as wanted and waits until tasks.reduce is ready with the tasks array (which has just one task here of course for testing).

The function of the code is ok. So I am wondering whether that is a problem of the Javascript parser of VS Code. When I put the same code snippet into the script part of an HTML file VS Code does not produce the warning. As well if I put it to a ts Typescript file.

Any idea to that would be appreciated

// nodejs 16 test function. VSCode 1.70.1 IDE
async function jobExecutorMinified() {
  const generateTask = () => {
    return () => {

      const p = new Promise(resolve =>  {
        setTimeout(() => {
          resolve();
        }, 5000);
      });

      // returning the promise of Promise.all -> warning w1
      return Promise.all([p]);

      // returning the promise directly -> no warnings
      // return p;

    }
  }
  const tasks = [generateTask()];

  /*w1*/await tasks.reduce((prevTask, currTask) => {
    return prevTask.then(() => {
      return currTask();
    });
  }, Promise.resolve());

  console.log('task chunking is ready');
}


jobExecutorMinified().then(() => {
  console.log('job executor minified returned');
});
Jamiec
  • 133,658
  • 13
  • 134
  • 193
Matthias
  • 26
  • 3
  • Are you using JSDoc? https://stackoverflow.com/questions/60368017/await-has-no-effect-on-the-type-of-this-expression – Jamiec Aug 11 '22 at 15:29
  • @Heiko: tasks.reduce returns a promise here even with just one task. You can check that with if (typeof p === 'object' && typeof p.then === 'function'). First the initial value (Promise is started as prevTask. In its then method the actual (and only) task function is called which returns the next promise. So await should actually get a promise. And it does so because the code really waits there for the 5 seconds. – Matthias Aug 12 '22 at 06:44
  • I wonder how VSCode can know what `tasks.reduce` will return without executing your code. What happens if you choose between the two `return` statements based on a random number? – Heiko Theißen Aug 12 '22 at 07:08
  • @Jamiec: good hint. I was not explicitely using JSDoc but when I add a JSDoc comment for the generatTask function with "@returns {Promise}" the warning disappears. So by any reason the Javascript parser seems not to be able to find out the return type of generateTask implicitely when "return Promise.all" is used. With JSDoc it uses that information. Probably I can ignore that phenomenon - but I don't like code which is not clean in relation to warnings - event if they are not correct. – Matthias Aug 12 '22 at 07:13
  • @Heiko: Good question. If generateTask would return values of different types (lets say one times a promise and one times a string or null) the type inference of Javascript could not find out a return type and should produce the await warning. Probably one of the pitfalls of an untyped language like Javascript and one of the advantages to use Typescript instead. – Matthias Aug 12 '22 at 07:25

1 Answers1

1

As discussed in the comments, this is just a false positive of the linter, which is not able to determine what reduce() returns (or probably: sees that Array.prototype.reduce is not an async function). Either give it some hints (type annotations, e.g. via jsdoc) or just ignore it.

However, you really shouldn't use reduce here. If you're using async/await anyway, just write a normal loop instead:

for (const currTask of tasks) {
  await currTask();
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Sorry for my answer, but @Bergi is right. Reduce is just a way for overcomplicating things when all you want to do is to execute on task after the other. – Bruno Marotta Jan 02 '23 at 14:07