Skip to content

第 8 题:setTimeout、Promise、Async/Await 的区别 #33

Open
@baoyipin

Description

@baoyipin

这题怎么没人答,我说下我粗浅的认识,抛砖引玉,欢迎指正和补充。
我觉得这题主要是考察这三者在事件循环中的区别,事件循环中分为宏任务队列和微任务队列。
其中settimeout的回调函数放到宏任务队列里,等到执行栈清空以后执行;
promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行;async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行。

Activity

JJL-SH

JJL-SH commented on Mar 11, 2019

@JJL-SH

宏观任务队列
微观任务队列
的区别

sisterAn

sisterAn commented on Mar 11, 2019

@sisterAn
Collaborator

1. setTimeout

console.log('script start')	//1. 打印 script start
setTimeout(function(){
    console.log('settimeout')	// 4. 打印 settimeout
})	// 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end')	//3. 打印 script start
// 输出顺序:script start->script end->settimeout

2. Promise

Promise本身是同步的立即执行函数, 当在executor中执行resolve或者reject的时候, 此时是异步操作, 会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行,打印p的时候,是打印的返回结果,一个Promise实例。

console.log('script start')
let promise1 = new Promise(function (resolve) {
    console.log('promise1')
    resolve()
    console.log('promise1 end')
}).then(function () {
    console.log('promise2')
})
setTimeout(function(){
    console.log('settimeout')
})
console.log('script end')
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout

当JS主线程执行到Promise对象时,

  • promise1.then() 的回调就是一个 task

  • promise1 是 resolved或rejected: 那这个 task 就会放入当前事件循环回合的 microtask queue

  • promise1 是 pending: 这个 task 就会放入 事件循环的未来的某个(可能下一个)回合的 microtask queue 中

  • setTimeout 的回调也是个 task ,它会被放入 macrotask queue 即使是 0ms 的情况

3. async/await

async function async1(){
   console.log('async1 start');
    await async2();
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}

console.log('script start');
async1();
console.log('script end')

// 输出顺序:script start->async1 start->async2->script end->async1 end

async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。

举个例子:

async function func1() {
    return 1
}

console.log(func1())

在这里插入图片描述
很显然,func1的运行结果其实就是一个Promise对象。因此我们也可以使用then来处理后续逻辑。

func1().then(res => {
    console.log(res);  // 30
})

await的含义为等待,也就是 async 函数需要等待await后的函数执行完成并且有了返回结果(Promise对象)之后,才能继续执行下面的代码。await通过返回一个Promise对象来实现同步的效果。

更多可见setTimeout、Promise、Async/Await

Fengziyin1234

Fengziyin1234 commented on Mar 29, 2019

@Fengziyin1234

上面的解释都很详细了。

我拿 babel es8 编译了下 async/await 结果是这样的

async function asyncTest() {
  const ret = await asyncFunction();
}

--->

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
  } catch (error) {
    reject(error);
    return;
  }
  if (info.done) {
    resolve(value);
  } else {
    Promise.resolve(value).then(_next, _throw);
  }
}

function _asyncToGenerator(fn) {
  return function() {
    var self = this,
      args = arguments;
    return new Promise(function(resolve, reject) {
      var gen = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
      }
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
      }
      _next(undefined);
    });
  };
}

function asyncTest() {
  return _asyncTest.apply(this, arguments);
}

function _asyncTest() {
  _asyncTest = _asyncToGenerator(function*() {
    const ret = yield asyncFunction();
  });
  return _asyncTest.apply(this, arguments);
}

await/async 是通过 Generator/function* 来实现的。 所以 async/await 的相关优势也来自于generator。 Generator 是一个可以暂停 function ,感觉推出 generator 的目的包括不仅限于 Callback Hell 和 Inversion of Control。 感觉整个 community 有在往那个方向走。

function* generator(i) {
  console.log('inside before')
  yield i;
  yield i + 10;
  console.log('inside after')
}

var gen = generator(10);
console.log('outside before')
console.log(gen.next().value);
console.log(gen.next().value);
console.log('outside after')
gen.next();

结果如下

> "outside before"
> "inside before"
> 10
> 20
> "outside after"
> "inside after" // 如果不加最后一个gen.next(); 就不会有这一行
MrRENGE

MrRENGE commented on Apr 6, 2019

@MrRENGE

1. setTimeout

console.log('script start')	//1. 打印 script start
setTimeout(function(){
    console.log('settimeout')	// 4. 打印 settimeout
})	// 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end')	//3. 打印 script start
// 输出顺序:script start->script end->settimeout

2. Promise

Promise本身是同步的立即执行函数, 当在executor中执行resolve或者reject的时候, 此时是异步操作, 会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行,打印p的时候,是打印的返回结果,一个Promise实例。

console.log('script start')
let promise1 = new Promise(function (resolve) {
    console.log('promise1')
    resolve()
    console.log('promise1 end')
}).then(function () {
    console.log('promise2')
})
setTimeout(function(){
    console.log('settimeout')
})
console.log('script end')
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout

当JS主线程执行到Promise对象时,

  • promise1.then() 的回调就是一个 task
  • promise1 是 resolved或rejected: 那这个 task 就会放入当前事件循环回合的 microtask queue
  • promise1 是 pending: 这个 task 就会放入 事件循环的未来的某个(可能下一个)回合的 microtask queue 中
  • setTimeout 的回调也是个 task ,它会被放入 macrotask queue 即使是 0ms 的情况

3. async/await

async function async1(){
   console.log('async1 start');
    await async2();
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}

console.log('script start');
async1();
console.log('script end')

// 输出顺序:script start->async1 start->async2->script end->async1 end

async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。

举个例子:

async function func1() {
    return 1
}

console.log(func1())

在这里插入图片描述
很显然,func1的运行结果其实就是一个Promise对象。因此我们也可以使用then来处理后续逻辑。

func1().then(res => {
    console.log(res);  // 30
})

await的含义为等待,也就是 async 函数需要等待await后的函数执行完成并且有了返回结果(Promise对象)之后,才能继续执行下面的代码。await通过返回一个Promise对象来实现同步的效果。

更多可见setTimeout、Promise、Async/Await
什么叫同步的立即执行函数?建议大佬看看规范中Promise的定义。

changed the title [-]第八题:setTimeout、Promise、Async/Await 的区别[/-] [+]第8题:setTimeout、Promise、Async/Await 的区别[/+] on Apr 26, 2019
changed the title [-]第8题:setTimeout、Promise、Async/Await 的区别[/-] [+]第 8 题:setTimeout、Promise、Async/Await 的区别[/+] on Apr 26, 2019
song-le-yi

song-le-yi commented on Jul 16, 2019

@song-le-yi

有个问题,如果promise的finally方法里面出错了怎么办呀,怎么捕获呀?

MrRENGE

MrRENGE commented on Jul 16, 2019

@MrRENGE

有个问题,如果promise的finally方法里面出错了怎么办呀,怎么捕获呀?

会返回一个 被reject 的promise对象。继续绑定catch函数可以捕获到

xuetupeng

xuetupeng commented on Jul 20, 2019

@xuetupeng
async1 start

写的很好,感谢大大的分享,我还有一个疑惑上面提到的Async/Await await执行的代码 ,会跳出线程,但是await上面的打印会出现在await执行打印的前面,意思是await前面的代码都会跳出线程(异步执行),只有await后面的代码才是同步执行这个意思吗?

rzh11111111

rzh11111111 commented on Jul 30, 2019

@rzh11111111

宏观微观?我记得promise的执行是在setimeout之前(好像),async/await是基于promise的

xuetupeng

xuetupeng commented on Jul 30, 2019

@xuetupeng

宏观微观?我记得promise的执行是在setimeout之前(好像),async/await是基于promise的

宏观吧,我其实就是比较奇怪,await前面的代码都跳出了线程吗,还是单纯就await 后面的执行跳出了线程, 也可能是我表达有问题, 为啥await以及前面代码的都会先打印 然后才是跳出线程执行外面的,最后才执行await下面的代码。

rzh11111111

rzh11111111 commented on Jul 30, 2019

@rzh11111111

宏观微观?我记得承诺的执行是在setimeout之前(好像),异步/ AWAIT是基于承诺的

宏观吧,我其实就是比较奇怪,等待前面的代码都跳出了线程吗,还是单纯就等待后面的执行跳出了线程,也可能是我表达有问题,为啥等待以及前面代码的都会先打印然后才是跳出线程执行外面的,最后才执行的await下面的代码。

就像setimeout是1,2,3这样的顺序来的,但是promise是1.1,1.2,promise是微观的,async,await基于promise也大概和promise一样

xuetupeng

xuetupeng commented on Jul 30, 2019

@xuetupeng

宏观微观?我记得承诺的执行是在setimeout之前(好像),异步/ AWAIT是基于承诺的

宏观吧,我其实就是比较奇怪,等待前面的代码都跳出了线程吗,还是单纯就等待后面的执行跳出了线程,也可能是我表达有问题,为啥等待以及前面代码的都会先打印然后才是跳出线程执行外面的,最后才执行的await下面的代码。

就像setimeout是1,2,3这样的顺序来的,但是promise是1.1,1.2,promise是微观的,async,await基于promise也大概和promise一样
恩,这个其实是了解的,就是Async/Await的有点没吃透,Await前面的语句 和Await后面的语句,两者间的差异, 就是为啥不是await 的内容 先输出 然后await上面和下面再输出

27 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @jumplee@rubyisapm@gaozf@JJL-SH@Fengziyin1234

        Issue actions

          第 8 题:setTimeout、Promise、Async/Await 的区别 · Issue #33 · Advanced-Frontend/Daily-Interview-Question