简体   繁体   中英

JavaScript promises .then and setTimeout ordering

 getAllUsers(): void { this.allUsers = this.userService.getUsers() .then(res => this.allUsers = res) .then(() => setTimeout( () => this.allUsers.forEach( user => console.log(user)), 2000 )) .then(() => setTimeout(this.restOfInit(), 4000)) .catch((error) => console.log(error))); // console.log(this.allUsers[0]); // setTimeout(() => console.log(this.allUsers[0]), 3000); } 

In the attached snippet, I would expect the logging of all the users to happen before the restOfInit function, since there's a difference of 2 seconds between the timeouts. However, what actually happens is that restOfInit is run first, logging a string to console, and all the users are logged to console after that. Why is this happening?

Two things:

1) The functions passed to setTimeout() execute asynchronously in approximately the number of milliseconds specified. You're likely aware of this. However, the calls to setTimeout() return (almost immediately) without regard to the time specified.

2) You want to pass this.restOfInit instead of this.restOfInit() . The former passes the function to setTimeout() . The latter invokes the function with no arguments and passes the return value (possibly undefined ) to setTimeout().

tldr;

.then(() => setTimeout(this.restOfInit(), 4000)) // Change this line

.then(() => setTimeout(this.restOfInit, 4000))  // to this

As correctly stated by @fvgs, the problem with the firing order you are seeing lies with the immediate invocation of this.restOfInit - its return value being passed to setTimeout instead of the function itself.

However using timeouts here defeats the point of promises. Promises should allow you to schedule the order precisely, and will execute as quickly as they can, rather than a guaranteed waiting period no matter how fast your request for users takes. Yours actually does not need to be chained at all as only the first callback needs the resolution values. It would be far easier to schedule like this...

    getAllUsers(): void {
      this.userService.getUsers()
        .then(res => {
          this.allUsers = res
          this.allUsers.forEach(user => console.log(user))
          this.restOfInit()
        })
        .catch((error) => console.log(error)));
    }

Also side note - the assigning of the this.allUsers = this.userService.getUsers() chain will be a promise, but then in the callback you assign this.allUsers = res which by the looks of it will be an array. I suspect this may be the reason you have used setTimeout as it could be overwriting it when you don't expect it.

Unless you need to further interact with the promise chain there is no need for this.allUsers = this.userService.getUsers() so i have omitted this in the code above

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