简体   繁体   中英

Scope of function passed to setInterval

I'm having trouble understanding function scope when called in setInterval.

When I declare an anonymous function directly inside the setInterval like this:

 let lastEventUUID = "some ID"; const interval = setInterval(async function() { console.log("lastEventUUID -> " + lastEventUUID); lastEventUUID = "another ID"; }, 1000); 

Everything work as expected, I get

lastEventUUID -> some ID
lastEventUUID -> another ID
...

But when I declare my function separatly

 async function myFunc(lastEventUUID) { console.log("lastEventUUID -> " + lastEventUUID); lastEventUUID = "another ID"; } 

And call set it in the setInterval :

let lastEventUUID = "some ID";
const interval = setInterval(myFunc, 1000, lastEventUUID);

The lastEventUUID is not updated in the next call, I get

lastEventUUID -> some ID
lastEventUUID -> some ID
...

What am I missing here ?

It's nothing to do with defining the function separately or not. In your first example, you're using the lastEventID variable that the function closes over. In your second example, you're using the lastEventID parameter that is passed to the function. Since setInterval passes it the same one every time, you see the same one every time.

If you do like-for-like, you can define it separately:

 async function myFunc() { // ^----- No parameter declared console.log("lastEventUUID -> " + lastEventUUID); lastEventUUID = "another ID"; } let lastEventUUID = "some ID"; const interval = setInterval(myFunc, 1000); // No argument given to pass to myFunc --^ 


Side note: You've defined your function as an async function . If your real function is using await in the function body, be sure that you have a try / catch around the full body of the function and that you handle any errors; otherwise, an error will result in an "Unhandled rejection" error (since the timer mechanism isn't going to do anything with the promise your function returns, including handling rejections). If your real function doesn't use await , there's no reason for it to be async .


Re your comment:

From what I understand this work because here lastEventUUID is declared in the global scope, but in my case, it is defined in another function...

No, it doesn't work because it's a global. It works because it's declared in the scope the function is defined in or a parent scope. It works just fine if that's the scope of a function. Example:

 function foo() { async function myFunc() { console.log("lastEventUUID -> " + lastEventUUID); lastEventUUID = "another ID"; } let lastEventUUID = "some ID"; const interval = setInterval(myFunc, 1000); } foo(); 

Globals are just an extreme case of this concept, which is called a closure . More: How do JavaScript closures work?

In fact, if we call that function twice, we see that there is a lastEventID variable for each of them (which is entirely private to the stuff defined within foo ):

 function foo(x) { async function myFunc() { console.log("x -> " + x + ", lastEventUUID -> " + lastEventUUID); lastEventUUID = "another ID"; } let lastEventUUID = "some ID"; const interval = setInterval(myFunc, 1000); } foo(1); foo(2); 

you can also achieve the same using Closures like this:

function myFunc(uuid) {
   return function(){
       console.log("lastEventUUID -> " + uuid);
       uuid = "another ID";
     }
}
let lastEventUUID = "some ID";
const interval = setInterval(myFunc(lastEventUUID), 1000);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM