0

I'm trying to translate all elements of the array wordList and pushing them to a new list translatedWordList, but because translate() is async the new list is empty when I callback or return it

function translateWordList(wordList, callback) {
  var translatedWordList = [];

  wordList.forEach((word) => {
    translate(word, (translation) => {
      translatedWordList.push(translation);
    });
  });

  callback(translatedWordList);
}

I tried to solve this by delaying the callback using a while loop that runs until the length of translatedWordList and wordList match, but the function translate is not logging anything

function translateWordList(wordList, callback) {
  var translatedWordList = [];

  wordList.forEach((word) => {
    translate(word, (translation) => {
      translatedWordList.push(translation);
      console.log(translation)
      counter++;
    });
  });

  while (translateWordList.length < wordList.length) {}
  callback(translatedWordList);
}

1 Answers1

1

Instead of using a Array#forEach, just use a normal for loop and make your function async so you can use the await keyword.

async function translateWordList(wordList, callback) {
  var translatedWordList = [];
  
  for(const word of wordList) {
    translatedWordList.push(await translate(word));
  }

  callback(translatedWordList);
}

If your translate function does not return a promise and only uses a callback, then you can promisify that function.

function translatePromise(word) {
  return new Promise((resolve, reject) => {
    translate(word, (translation, err) => {
      // assuming your callback signals an error in the second parameter
      if(err) {
        reject(err);
        return;
      }
      resolve(translation);
    });
  });
}

Then replace the translate(word) call in the first example with translatePromise(word).

However, if you don't want to work with async/await you could do something like this.

function translateWordList(wordList, callback) {
  Promise.all(wordList.map((word) => {
    return new Promise((resolve) => {
      translate(word, resolve);
    });
  }))
  .then(callback);
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
  • the problem is that translate() takes a lot of time to execute so I need it as an async function is there any faster alternatives than promises? – Joonius Jan 16 '23 at 16:07
  • @Joonius did you try the last option? It'll run all your promises at the same time with "Promise.all"? – kemicofa ghost Jan 16 '23 at 16:13
  • And in general, if your method is asynchronous then unfortunately you're limitted to the speed of which it takes to resolve. The fastest you can go is to run all your promises at the same time. – kemicofa ghost Jan 16 '23 at 16:16
  • Is it possible to run all the promises at the same time? If so, how do I do it? – Joonius Jan 16 '23 at 16:30
  • @Joonius the last example runs all your promises at the same time with Promise.all. You can read more about it here. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all – kemicofa ghost Jan 16 '23 at 16:31