JavaScript的执行顺序

前言

在说 JavaScript 的执行顺序之前,我们先回答一下以下几组程序的输出结果

第 1 组

const output = (v) => {
  console.log(v);
};

setTimeout(() => {
  console.log(1);
}, 0);
output(2);
console.log(3);

// 2 3 1

第 2 组

new Promise((resolve) => {
  console.log(1);
  resolve();
  new Promise((resolve) => {
    console.log(2);
    resolve();
  }).then(() => {
    console.log(3);
    new Promise((resolve) => {
      console.log(4);
      resolve();
    }).then(() => {
      console.log(5);
      new Promise((resolve) => {
        console.log(6);
        resolve();
      }).then(() => {
        console.log(7);
      });
    });
  });
}).then(() => {
  console.log(8);
  new Promise((resolve) => {
    console.log(9);
    resolve();
  }).then(() => {
    console.log(10);
  });
});

// 1 2 3 4 8 9 5 6 10 7

看完上面两组案例,是不是会产生这样的疑惑,为什么输出的结果是这样的,别着急,下面我们来详细分析

一、简述

我们都知道 JavaScript 是单线程语言,这表明 JavaScript 同时只能执行一个任务,但执行顺序却并不是自上而下的

这一点,通过上面的案例我们就已经知道了,那么执行规律究竟是什么呢?

要分析 JavaScript 的执行规律,就不得不说一下 JavaScript 的任务分类, JavaScript 分为同步任务异步任务

二、同步任务

同步任务:立即执行的任务,解析时遇到同步任务会被主线程立即读取并执行

同步任务:

  1. console.log()
  2. new Promise()
  3. 直接调用 function()

三、异步任务

异步任务:异步执行的任务,解析时遇到异步任务,直接丢到任务队列中,不会立即读取和执行

异步任务又分为宏任务微任务,执行时优先执行微任务,后执行宏任务

微任务

  1. promise.then()
  2. nextTick()

宏任务

  1. setTimeout()
  2. setInterval()

四、分析

JavaScript 在执行任务之前会先自上而下遍历所有任务,在遍历的过程中如果遇到同步任务则直接执行,执行完成后继续往下遍历,如果遇到异步任务,则放入任务队列中(微任务放入微任务队列,宏任务放入宏任务队列),第一遍遍历完成后,从微任务队列中继续遍历,遇到同步任务立即执行,遇到异步任务继续放入任务队列中,不断的重复这个过程,直到所有任务全部执行完毕,这个不断重复遍历执行的过程,就叫做事件循环

  • 第 1 次循环:遍历所有任务,遇到同步任务立即解析并执行,遇到异步任务则放入任务队列中暂不解析
  • 第 2 次循环:从任务队列中微任务开始循环,重复第 1 次的过程
  • 第 n 次循环:所有同步任务、微任务都执行完毕后,开始循环宏任务,同样重复第 1 次的过程

第 1 组程序 - 解析

const output = (v) => {
  console.log(v);
};

// 异步宏任务,放入任务队列,暂不执行
setTimeout(() => {
  console.log(1);
}, 0);

// 同步任务,立即执行
output(2);

// 同步任务,立即执行
console.log(3);

第 2 组程序 - 解析

new Promise((resolve) => {
  console.log(1);
  resolve();
  new Promise((resolve) => {
    console.log(2);
    resolve();
  }).then(() => {
    console.log(3);
    new Promise((resolve) => {
      console.log(4);
      resolve();
    }).then(() => {
      console.log(5);
      new Promise((resolve) => {
        console.log(6);
        resolve();
      }).then(() => {
        console.log(7);
      });
    });
  });
}).then(() => {
  console.log(8);
  new Promise((resolve) => {
    console.log(9);
    resolve();
  }).then(() => {
    console.log(10);
  });
});

这个稍微复杂一点,但也很好分析,我们来模拟一下事件循环

第 1 次循环

// 同步任务,立即执行
console.log(1)
// 同步任务,立即执行
 new Promise((resolve) => {
    console.log(2);
    resolve();
  })
// 异步任务,放入任务队列
.then(() => {
    console.log(3);
    new Promise((resolve) => {
      console.log(4);
      resolve();
    }).then(() => {
      console.log(5);
      new Promise((resolve) => {
        console.log(6);
        resolve();
      }).then(() => {
        console.log(7);
      });
    });
  });
// 异步任务,放入任务队列
.then(() => {
  console.log(8);
  new Promise((resolve) => {
    console.log(9);
    resolve();
  }).then(() => {
    console.log(10);
  });
});

第一次循环输出结果如下

// 1 2

第 2 次循环

// 同步任务,立即执行
console.log(3);
// 同步任务,立即执行
new Promise((resolve) => {
  console.log(4);
  resolve();
}
// 异步任务,放入任务队列
.then(() => {
      console.log(5);
      new Promise((resolve) => {
        console.log(6);
        resolve();
      }).then(() => {
        console.log(7);
      });
    });
// 同步任务,立即执行
console.log(8);
// 同步任务,立即执行
new Promise((resolve) => {
  console.log(9);
  resolve();
})
// 异步任务,放入任务队列
.then(() => {
    console.log(10);
  });

第 2 次循环输出结果如下

// 3 4 8 9

第 3 次循环

// 同步任务,立即执行
console.log(5);
// 同步任务,立即执行
console.log(6);
// 异步任务,放入任务队列
.then(() => {
    console.log(7);
  });
// 同步任务,立即执行
console.log(10);

第 3 次循环输出结果如下

// 5 6 10

第 4 次循环

// 同步任务,立即执行
console.log(7);

第 4 次循环输出结果如下

// 7

所有任务全部执行完毕,循环结束,最终输出结果如下

// 1 2 3 4 8 9 5 6 10 7
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温其如玉_zxh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值