How to make an async then?

2019-09-03 10:35发布

问题:

Basically I am trying to play around to understand more of async/await and promise in JS. I'm trying to make Hello comes in between finished! and third finish!!. So the best guess is, making second then asnyc and await for console.log('Hello'). I've tried both ways below but both are not working as expected.

Approach A

let promise = new Promise((res,rej)=>{
  res();
});

promise.then(() => {
  console.log('finished!')
}).then(() => {
  setTimeout(async function(){     
    await console.log("Hello"); }, 3000); //async/await at setTimeout level
}).then(() => {
  console.log('third finish!!')
})

Approach B:

let promise = new Promise((res,rej)=>{
      res();
    });

    promise.then(() => {
      console.log('finished!')
    }).then(async () => { //async/await at thenlevel
      await setTimeout(function(){     
        console.log("Hello"); }, 3000); 
    }).then(() => {
      console.log('third finish!!')
    })

回答1:

You need the second section to be a Promise, and return it from the .then so that it's properly chained between the first and the third. setTimeout doesn't return a Promise, you have to explicitly construct a Promise instead:

let promise = new Promise((res,rej)=>{
  res();
});

promise.then(() => {
  console.log('finished!')
}).then(() => {
  return new Promise(resolve => {
    setTimeout(function(){     
      console.log("Hello");
      resolve();
    }, 1000);
  });
}).then(() => {
  console.log('third finish!!')
})

Or, using await, use await new Promise followed by the same Promise construction and the setTimeout:

let promise = new Promise((res, rej) => {
  res();
});

promise.then(() => {
  console.log('finished!')
}).then(async() => {
  await new Promise(resolve => {
    setTimeout(function() {
      console.log("Hello");
      resolve();
    }, 1000);
  });
}).then(() => {
  console.log('third finish!!')
})



回答2:

Another approach is to write an asynchronous setAsyncTimeout function (this hasn't been thoroughly tested, may need tweaks):

async function setAsyncTimeout(callback, interval) {
    return new Promise( (resolve, reject) => {
        setTimeout(() => {
            try {
                let inner = callback()
                if (inner && inner.then) {
                    inner.then(resolve, reject)
                } else {
                    resolve(inner)
                }
            } catch(e) {
                reject(e)
            }
        }, interval)
    })
}

Testing via your example:

let promise = new Promise((res,rej)=>{
  res();
});

promise.then(() => {
  console.log('finished!')
}).then( setAsyncTimeout(function(){     
    console.log("Hello"); }, 3000); 
}).then(() => {
  console.log('third finish!!')
})

Testing via your example (with another promise):

let promise = new Promise((res,rej)=>{
  res();
});

promise.then(() => {
  console.log('finished!')
}).then(async () => { //async/await at thenlevel
  await setAsyncTimeout(function(){     
    console.log("Hello");
    return setAsyncTimeout(() => console.log("world"), 3000)
  }, 3000); 
}).then(() => {
  console.log('third finish!!')
})

Cleaner example:

let promise = new Promise((res,rej)=>{
  res();
});

promise.then(() => {
  console.log('finished!')
}).then(() => {
  return setAsyncTimeout(() => { console.log("Hello"); }, 3000)
}).then(() => {
  console.log('third finish!!')
})