Skip to content

关于JavaScript代码执行顺序

例一

javascript
async function async1() {    
  console.log(1);    
  await async2();    
  console.log(2);
}
async function async2() {    
  console.log(3);
}

async1();

setTimeout(() => console.log(4), 0);

new Promise(resolve => {
  resolve();
  console.log(5);
}).then(() => { 
    console.log(6);
    Promise.resolve().then(()=>{
        console.log(7);
    })
});

console.log(8);
Details

// 正确答案:13582674

TIP

  1. 每一个当下,正在被执行的JS代码是放在JS的主线程(我们叫JS Stack)的。同步的代码会按照代码顺序依次放入JS Stack,然后按照放入的顺序依次执行。

  2. 异步的代码会被放入Macrotask或者Microtask,promise属于Microrask。这篇文章,我们先忽略Macrotask。

  3. 异步的代码一定是要等到同步的代码执行完了才执行。也就是说,直到JS Stack为空,Microtask里面的代码才会被提到JS Stack,然后被执行。

  4. new Promise()和.then()方法属于同步代码。

  5. .then()时只是注册callback方法,并不会把callback方法加入Microtask

  6. .then(resolveCallback, rejectCallback)里面的resolveCallback, rejectCallback的执行属于异步代码,会在执行了resolve之后被放入Microtask。

  7. resolve()被调用会起到2点作用

(1). Promise由pending状态变为resolved

(2). 遍历这个promise上所注册的所有的resolveCallback方法,依次加入Microtask。

  1. 其实async await实质只是promise.then 的语法糖,带 async 关键字的函数,它使得你的函数的返回值必定是 promise 对象,如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装,如果async关键字函数显式地返回promise,那就以你返回的promise为准。对于await来说,如果await后面是不是promise对象,那么await会阻塞后面的代码,先执行async函数外面的同步代码,同步代码执行完毕,再回到async内部,把这个非promise的东西,作为await表达式的结果。 如果await后面是promise对象,那么他会在async外部的同步代码执行完毕之后等到promise对象fulfilled,然后把resolve的参数作为await表达式的运行结果。

一句话解释:await会阻塞后面的任务,指的是下一行代码,await同行代码是会立即执行的。

javascript
async function async1() {    
  console.log(1);    
  await async2();    
  console.log(2);
}
async function async2() {    
  console.log(3);
}

相当于:

javascript
async function async1() {    
  console.log(1);    
  new Promise((resolve) => {
    console.log(3);
    resolve();
  }).then(() => {
    console.log(2);
  })
}

例二

javascript
async function async1() {
    console.log('async1 start');
    await async2();                
    console.log('async1 end');
}
async function async2() {
    await async3(); 
    console.log('async2');
}
async function async3() {
    console.log('async3');
}
console.log('script start');
setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

结果是:

Details

script start

async1 start

async3

promise1

script end

async2

promise2

async1 end

undefined

setTimeout