1

I am trying to learn the concepts of async/await in javascript. I tried a simple code, to wait for a create post function to finish before calling the getPosts function, but the newly created post is not showing up. This is what I have tried out.

const posts = [{
    title: "Post One",
    body: "This is post one"
  },
  {
    title: "Post Two",
    body: "This is post two"
  }
]

const newpost = {
  title: "Post Three",
  body: "This is post three"
}

function getPosts() {
  setTimeout(() => {
    let output = '';
    posts.forEach((post, index) => {
      output += `<li>${post.title} : ${post.body}</li>`;
    });
    document.body.innerHTML = output;
  }, 1000);
}

function createPost(post) {
  setTimeout(() => {
    posts.push(post);
  }, 2000);
}

async function init() {
  await createPost(newpost);
  getPosts();
}

init();

Can anyone point out what I am doing wrong?

Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
Sneharghya Pathak
  • 990
  • 1
  • 9
  • 19
  • 1
    `createPost()` doesn't return a promise – ProEvilz Jun 02 '19 at 12:39
  • 1
    async/await only works with promises. – Nicholas Tower Jun 02 '19 at 12:40
  • Similar to https://stackoverflow.com/questions/33289726/combination-of-async-function-await-settimeout. Maybe this helps you. – fl9 Jun 02 '19 at 12:40
  • 1
    All the answers below which says to create promise are mixing two concepts. Yes, await works with promises, but await is better used with async as mentioned in CMS's answer [below](https://stackoverflow.com/a/56415196/1955268) – prinkpan Jun 02 '19 at 13:08

7 Answers7

3

createPost should return promise like below

function createPost(post) {
return new Promise((resolve,reject)=> {
setTimeout(() => {
    posts.push(post);
    resolve();
  }, 2000);
});  
}
  • Isn't using promises with await mixing two similar concepts? Promises are better used with `.then()` and `await` is better used with `async` – prinkpan Jun 02 '19 at 13:10
  • By default async returns promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function – P D K Pavan Kumar Jun 02 '19 at 13:16
2

The problem is that createPost doesn't return a promise.

You can either return a promise manually:

function createPost(post) {
  return new Promise((resolve) => {
  setTimeout(() => {
    posts.push(post);
    resolve();
  }, 2000);
  });  
}

But who want's to create promises by hand ? And since you want to practice with async functions, have createPost be an async function by itself.

I'm also extracting the setTimeout calls to a small wait async utility function:

const posts = [{
    title: "Post One",
    body: "This is post one"
  },
  {
    title: "Post Two",
    body: "This is post two"
  }
]

const newpost = {
  title: "Post Three",
  body: "This is post three"
}

const sleep = time => new Promise(resolve => setTimeout(resolve, time));

async function getPosts() {
  await sleep(1000);
  let output = '';
  posts.forEach((post, index) => {
    output += `<li>${post.title} : ${post.body}</li>`;
  });
  document.body.innerHTML = output;
}

async function createPost(post) {
    await sleep(2000);
    posts.push(post);
}

async function init() {
  await createPost(newpost);
  getPosts();
}

init();
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
0

May I know why you're using setTimeout() function? removing the setTimeout() makes the code just work fine

 const posts = [{
    title: "Post One",
    body: "This is post one"
  },
  {
    title: "Post Two",
    body: "This is post two"
  }
]

const newpost = {
  title: "Post Three",
  body: "This is post three"
}

function getPosts() {
    let output = '';
    posts.forEach((post, index) => {
      output += `<li>${post.title} : ${post.body}</li>`;
    });
    document.body.innerHTML = output;
}

function createPost(post) {
    posts.push(post);
}

async function init() {
  await createPost(newpost);
  getPosts();
}

init();

Here is the working code pen: Code Pen Link

fingers10
  • 6,675
  • 10
  • 49
  • 87
0

createPost should return a promise so the function should be like that

function createPost(post) {
  return new Promise( resolve => 
    setTimeout(() => {
      posts.push(post);
      resolve()
    }, 2000);
  });
}
Muho
  • 3,188
  • 23
  • 34
0

The await command expects the calling function to return a promise. Such a function usually execute an asynchronous command and resolves the promise when the command is successful.

var posts = [];

function createPost(post) {

  return new Promise(function(resolve, reject){

    setTimeout(() => {
       posts.push(post);
       resolve();         //<- resolved the promise here
    }, 2000);


  })   

}


async function testAsync() {

    await createPost('a post');
    
    console.log(posts)
    
}

testAsync();
    
    

In this case, although Array.push() doesn't do any async operation, you call it via setTimeout to do it in an async fashion.

Charlie
  • 22,886
  • 11
  • 59
  • 90
0

Async/await only works with promises, so you need to wrap whatever code you have in createPost() in a promise, return it and then resolve it to indicate that it doesn't have to be awaited anymore and the code can continue executing. I made a tiny example from your code where you can see how it works:

function getPosts(){
  setTimeout(()=>{
    console.log( "get posts" );
  }, 1000);
}

function createPost(post){
  return new Promise( res => {
    setTimeout(()=>{
      console.log( "post created" );
      res();
    }, 2000);
  } );
}

async function init(){
  await createPost();
  getPosts();
}

init();
Yannick K
  • 4,887
  • 3
  • 11
  • 21
0

createPost is not any async function, await will listen only to promise and async function, to be able to await that kind of setTimeout, and to apply ur intent, u need promise with done method to tell Nodejs to end listening

function createPost(post) {
  return new Promise(done){
    setTimeout(() => {
      posts.push(post);
      done()
    }, 2000);
  }
}
Vengleab SO
  • 716
  • 4
  • 11