Mohsen
Mohsen

Reputation: 1118

Using Promises and Async/Await in JavaScript

I've read some articles about Promises and async/await in JavaScript to understand its point, but yet have not completely comprehended it; so, I'll explain an example here and want you to help me to comprehend the mechanism. The following code are in NestJS.

Here is my auth.service.ts:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { UserRepository } from './user.repository';

@Injectable()
export class AuthService {
  constructor(
    @InjectRepository(UserRepository)
    private userRepository: UserRepository
  ) {}

  createUser(): void {
    this.userRepository.createUser();

    console.log('Here I want to do some other works simultaneously while this.userRepository.createUser() is also processing');
  }
}

Here is my user.repository.ts:

import { EntityRepository, Repository } from 'typeorm';
import { User } from './user.entity';

@EntityRepository(User)
export class UserRepository extends Repository<User> {
  async createUser(): Promise<void> {
    await this.makeUser();
  }

  async makeUser(): Promise<void> {
    return new Promise((resolve, reject) => {
      // Simulating making a user which will take some time
      let x = 1;
      for (let i = 0; i < 1000000000; i++) {
        x++;
      }

      console.log('User Created');

      resolve();
    });
  }
}

What I expect based on the above code and what I have learned so far, is that the line console.log('Here I want to do some other works simultaneously...') to work before completion of the line this.userRepository.createUser(), but this does not happen and I get "User Created" logged first and then I get "Here I want to do some other works simultaneously...".

Where am I wrong?

Upvotes: 0

Views: 588

Answers (3)

Martin Jaskulla
Martin Jaskulla

Reputation: 482

Multithreading is possible in JavaScript using Workers.

However since JavaScript is single-threaded, things like Workers are provided by the environment (NodeJS or the browser) you run your JavaScript in. Making http requests or calling setTimeout are good examples of something similar. They are not part of JavaScript itself, but are implemented by the browser or NodeJS instead.

For an example of async work run the snippet below in some JS playground:

(async function () {
 function makeRequest() {
    return fetch('https://jsonplaceholder.typicode.com/todos/1').then(response => response.json()).then(json => console.log("Http request complete", json))
  }
  const promise = makeRequest()
  console.log('Here I want to do work while the http request is made')
  await promise
  console.log("Here I want to continue after http request is complete")
})();

If you want to learn more I recommend this talk and this article

Upvotes: 2

Marco
Marco

Reputation: 7277

Where am I wrong?

JavaScript is single threaded, so only one piece of code can run at any time.

There are some exceptions like HTTP requests (these are handed off to a thread).

Asynchronous does not mean "parallel".

Synchronous execution is ordered: one thing happens after another:

  1. Do Task 1
  2. Handle result of Task 1
  3. Do Task 2
  4. Handle result of Task 2

Asynchronous execution is not ordered (hence asynchronous):

  1. Do Task 1
  2. Do Task 2
  3. Handle result of Task 1
  4. Handle result of Task 2

You might wonder "Well in your asynchronous example, Do Task 1 and Do Task 2 are executed in parallel". This is not true, asynchronicity is not about parallelism, it's about the "out-of-order" execution.

The power behind asynchronicity is that, if implemented correctly, allows multiple code segments to run "out-of-order" giving the impression, they are run in parallel. *

*This is not to say, that asynchronous code does not allow for parallelism. It's actually the case that asynchronous code allows for parallel processing to happen, since the result is dealt with when it's ready. Of course, if you only ever have one thread, then asynchronicity does not give you any real benefit at all.

Upvotes: 0

Patrick Roberts
Patrick Roberts

Reputation: 51977

The problem is that your makeUser() function isn't actually asynchronous. Just because it returns a promise doesn't mean that the work it performs won't block code paths that don't await its completion. JavaScript is still single-threaded, and until the for loop completes, no other code is able to execute.

A more reasonable mock implementation might look like this:

  async makeUser(): Promise<void> {
    return new Promise((resolve, reject) => {
      // Simulating making a user which will take some time
      setTimeout(() => {
        console.log('User Created');

        resolve();
      }, 1000);
    });
  }

Note that setTimeout() is an example of a truly asynchronous function: it schedules a function to be called some time later without blocking the thread. Also note that because JavaScript is single-threaded, the callback function scheduled by setTimeout() will not be executed until all other code paths are finished executing, so this goes both ways, and the following will not cause two simultaneously executing code paths:

setTimeout(() => {
  console.log('scheduled');
}, 50);

let later = Date.now() + 100;

while (later > Date.now()) {}

console.log('done');

In this case, scheduled can never come before done, it will always print afterwards.

Upvotes: 2

Related Questions