3

I am using eval function to evaluate the strings and I am applying await on eval function so that I will get all the values. But the await is not working

My code is something like this:-

if (matchCard.card.status != "notstarted") {
    return new Promise((resolve) => {
        questionSetObj.forEach(async ([key, value], index) => {
            let thisVal = await eval(value.functionName)(value, key);
            console.log("thisVal....", thisVal)
            if (thisVal) {
                if (thisVal[key] != "NotFound") answerSet[key] = thisVal[key]
            }
            console.log("answerSet", answerSet);
            answerSetArray.push(answerSet);
            if (index === questionSetObj.length - 1) resolve(answerSetArray);
        });
    })
}

Variables used in the above functions, their values:-

var value = { teamTwoId: 'wi', matchId: 'iccrzt20_2020_vg_g7', question: 'Which team will win the match?', functionName: 'matchWinnerTeam', options: { option2: 'West Indies', option1: 'Afghanistan' }, teamOneId: 'afg' }

In value obj, functionName: 'matchWinnerTeam'. matchWinnerTeam() is a function to evaluate the answer of the question.

var key = Q1

Similarly, I have 5 questions sets similarly like this.

Problem Statement:-

My answerSet object value should return values something like this:- answerSet = { Q5: 'option2', Q3: 'option2', Q2: 'option2', Q4: 'option1', Q1: 'option2' } But actually it returns values something like this whenever I run this function on my node js server:-
{ Q5: 'option2', Q3: 'option2', }, { Q1: 'option2', Q4: 'option2', } ..... and so on.

Issue what I found is that eval function has to wait until it returns all the values from Q1 to Q5 but await is not working on eval(). It evaluates answers of two questions and it returns those two values, it is not waiting for rest 3 answers to get evaluated.

So can I use await on eval() like this or there will be some alternate method to perform this task?

Please Help. Thank You

5
  • 5
    Please avoid using eval. You only use it to fetch a function by name - you can instead pass have an object where you get the function by name or better yet, questionSetObj can directly use the functions, so you don't need to eval them but execute them Commented Jul 22, 2020 at 8:43
  • You can only await a promise, eval can return a promise, it depends on what you are evalling. Commented Jul 22, 2020 at 8:44
  • 1
    Does this answer your question? await is only valid in async function - eval in async Commented Jul 22, 2020 at 9:00
  • @VLAZ Basically You are saying i can directly use like this (value.functionName)(value, key); No need of eval. Commented Jul 22, 2020 at 9:14
  • @AmanSingh only if you directly pass the functions as references, not if you pass function names. So you need [{f: function() { console.log("one"); } }, {f: function() { console.log("two") } }] instead of [{functionName: "functionOne" }, { ffunctionName: "functionTwp" }]. Commented Jul 22, 2020 at 10:00

1 Answer 1

1

Well, I don't think that using eval is evil, of course while you know what you are doing! In your case, as I understand, you want to wait for eval to complete. So you can create promise wrapper and put resolve inside your eval code, i.e like this:

let toeval = `
  // Iteration number
  let i = 100;

  // Finish function
  const finish = () => {
    // Resolve
    resolve('This is data from eval');
  }

  // Delay function
  const delay = () => {
    setTimeout(() => {
      if(i) {
        i--;
        delay();
      } else finish();
    }, 10);
  }

  // Run delay
  delay();
`;

// Wait for eval wrapper
const waitEval = (ev) => {
  return new Promise((resolve, reject) => {
    eval(ev);
  });
};
                     
// Main function
(async () => {
  // Start message
  console.log(`Starting and waiting for eval to complete...`);
  
  // Run and wait for eval
  const x = await waitEval(toeval);
  console.log(`Result from eval: ${x}`);
  
  // Continue
  console.log(`Finished! Continue program...`);
})();

But keep in mind, if you want to do the same as above but in more secure way, use new Function instead of eval:

let toeval = `
  // Iteration number
  let i = 100;

  // Finish function
  const finish = () => {
    // Resolve
    resolve('This is data from eval');
  }

  // Delay function
  const delay = () => {
    setTimeout(() => {
      if(i) {
        i--;
        delay();
      } else finish();
    }, 10);
  }

  // Run delay
  delay();
`;

// Wait for new Function wrapper
const waitFn = (ev) => {
  return new Promise((resolve, reject) => {
    new Function('resolve', ev)(resolve);
  });
};
                     
// Main function
(async () => {
  // Start message
  console.log(`Starting and waiting for eval to complete...`);
  
  // Run and wait for eval
  const x = await waitFn(toeval);
  console.log(`Result from eval: ${x}`);
  
  // Continue
  console.log(`Finished!`);
})();

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.