David J.
David J.

Reputation: 1913

Nested Promise.all functions producing unexpected results

I'm trying to translate entries from a JSON file into another language using the Deepl API. The JSON file looks like this:

[
    {
        "pre": "here is a sample",
        "body": "here is the body",
        "answers": ["answer one", "answer two"],
        "correct": "answer one"
    },
    {
        "pre": "here is a sample",
        "body": "here is the body",
        "answers": ["answer one", "answer two"],
        "correct": "answer one"
    }
]

I'm using the following functions to do this:

const { exec } = require('child_process');
const fs = require('fs')
const authKey = 'somekey'

module.exports = {

    translateText(text, targetLang){
        return new Promise(function(accept, reject){
            var command=`curl https://api.deepl.com/v2/translate \
    -d auth_key=${authKey} \
    -d "text=${text}"  \
    -d "target_lang=${targetLang}"`;

            exec(command, (err, stdout, stderr) => {
                if (err) {
                    return;
                }
                accept(stdout);
            });

        });
    },
    translateFile(src, targetLang){
        var self=this;
        return new Promise(function(accept, reject){
            fs.readFile(src, function(err, data){
                if(err){
                    return
                }
                const contents=data.toString();
                var arr=JSON.parse(contents);// [{id: 1, pre: '', 'body', 'answers': ['sdf', 'adfwe'], correct: 'sdf'}]

                Promise.all(arr.map(question => {

                    var pre = question.pre=self.translateText(question.pre, targetLang);
                    var body = question.body=self.translateText(question.body, targetLang);
                    var correct = question.correct=self.translateText(question.correct, targetLang);
                    var answers = Promise.all(question.answers.map(answer => {
                        return self.translateText(answer, targetLang);
                    })).then(translated => {
                        answers = translated;
                        Promise.all([pre, body, correct]).then(()=>{
                            question.pre=pre
                            question.body=body
                            question.correct=correct
                            question.answers=answers
                            return question;
                        });
                    });
                    console.log('the answers are: ' + answers);
                    return Promise.all([pre, body, correct, answers]).then(val => {

                        return question
                    });
                })).then(val => {
                    accept(val);
                });
            });
        });

    }
}

I am expecting an array to be returned that looks exactly like the original JSON array, but with translated entries. Somewhere I went wrong with my promise logic, however. Can anyone help me understand this?

Here's what executing it does:

> var t=require('./translate.js')
undefined
> t.translateFile('./sample_data.json', 'DE').then(data => {console.log(data)})
Promise {
  <pending>,
  domain:
   Domain {
     domain: null,
     _events:
      { removeListener: [Function: updateExceptionCapture],
        newListener: [Function: updateExceptionCapture],
        error: [Function: debugDomainError] },
     _eventsCount: 3,
     _maxListeners: undefined,
     members: [] } }
> the answers are:
Promise {
  <pending>,
  domain:
   Domain {
     domain: null,
     _events:
      { removeListener: [Function: updateExceptionCapture],
        newListener: [Function: updateExceptionCapture],
        error: [Function: debugDomainError] },
     _eventsCount: 3,
     _maxListeners: undefined,
     members: [] } }
the answers are:
Promise {
  <pending>,
  domain:
   Domain {
     domain: null,
     _events:
      { removeListener: [Function: updateExceptionCapture],
        newListener: [Function: updateExceptionCapture],
        error: [Function: debugDomainError] },
     _eventsCount: 3,
     _maxListeners: undefined,
     members: [] } }
[ { pre:
     Promise {
       '{"translations":[{"detected_source_language":"EN","text":"hier ist ein Beispiel"}]}',
       domain: [Domain] },
    body:
     Promise {
       '{"translations":[{"detected_source_language":"EN","text":"hier ist die Leiche"}]}',
       domain: [Domain] },
    answers:
     [ '{"translations":[{"detected_source_language":"EN","text":"eine Antwort geben"}]}',
       '{"translations":[{"detected_source_language":"EN","text":"zweite Antwort"}]}' ],
    correct:
     Promise {
       '{"translations":[{"detected_source_language":"EN","text":"eine Antwort geben"}]}',
       domain: [Domain] } },
  { pre:
     Promise {
       '{"translations":[{"detected_source_language":"EN","text":"hier ist ein Beispiel"}]}',
       domain: [Domain] },
    body:
     Promise {
       '{"translations":[{"detected_source_language":"EN","text":"hier ist die Leiche"}]}',
       domain: [Domain] },
    answers:
     [ '{"translations":[{"detected_source_language":"EN","text":"eine Antwort geben"}]}',
       '{"translations":[{"detected_source_language":"EN","text":"zweite Antwort"}]}' ],
    correct:
     Promise {
       '{"translations":[{"detected_source_language":"EN","text":"eine Antwort geben"}]}',
       domain: [Domain] } } ]

Upvotes: 0

Views: 97

Answers (1)

Ashley
Ashley

Reputation: 917

You're missing an equals sign after var answers:

                var answers =
                Promise.all(question.answers.map(answer => {
                    return self.translateText(answer, targetLang);
                })).then(translated => {
                    answers = translated;
                    Promise.all([pre, body, correct]).then(()=>{
                        question.pre=pre
                        question.body=body
                        question.correct=correct
                        question.answers=answers
                        return question;
                    });
                });

BUT since that wasn't the issue (and you posted your result, thanks!) my best guess is that the issue lies here:

                    Promise.all([pre, body, correct]).then(()=>{
                        question.pre=pre
                        question.body=body
                        question.correct=correct
                        question.answers=answers
                        return question;
                    });

You should be catching the array of what is completed in the .then() and setting question.pre, question.body, and question.correct as those values. Instead, this is setting them to the Promises you defined above:

                Promise.all([pre, body, correct]).then((results)=>{
                    question.pre=results[0]
                    question.body=results[1]
                    question.correct=results[2]
                    question.answers=answers
                    return question;
                });

You will still need to parse the text-only out of the JSON.

Upvotes: 1

Related Questions