Search code examples
javascriptasynchronouspromisesettimeouteval

Clarifications on MDN "Use functions instead of evaluating snippets of code" - why's that?


On MDN article about eval there's a paragraph titled Use functions instead of evaluating snippets of code, in the example code there's a reference about setTimeout(). I can't grasp why this advice/command, so, keeping the setTimeout() reference, could someone point me out why these codes work as expected:

function timedPromise(){
  return new Promise((resolve) => {
    setTimeout(( ) => {resolve(console.log('Promise resolved!'))}, 1000)
  })
};
 
function timedPromise2(){
  return new Promise((resolve) => {
    setTimeout(function(){resolve(console.log('Another promise resolved!'))}, 2000)
  })
};
timedPromise();
timedPromise2();
/*output:
Promise {<pending>}
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
Promise resolved! //after at least 1s
Another promise resolved! //after at least 2s
*/

While this code won't?

function timedPromise(){
  return new Promise((resolve) => {
    setTimeout(resolve(console.log('I resolved!')), 1000)
  })
};
 
timedPromise();
/*output:
I resolved! //immediate
Promise {<fulfilled>: undefined}
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
*/

I understand the browser evaluates the code snippet as a string instead of a function, and then interprets it and executes it immediately instead of waiting for the delay of setTimeout() to pass.

Why though?

Why/when should I use wrapper functions instead of code snippets as parameters? Is it a thing related only to asynchronicity?


Solution

  • When you write functionName(), the () call the function immediantly.

    So when you write setTimeout(resolve(console.log('I resolved!')), 1000) it:

    • Calls console.log first to pass its return value into resolve;
    • Calls resolve to pass it's value into setTimeout;
    • Calls setTimeout.

    When you wrap a function in a lambda, you're passing a reference to that function through, rather than calling it immediantly. It might be clearer to see like this:

    function doLog() { console.log("Hello, world!"); }
    
    // Calls doLog instantly, passes in return value of undefined
    setTimeout(doLog(), 1000); 
    
    // Passes in a reference to doLog, which setTimeout will then call later
    setTimeout(doLog, 1000);