JavaScript事件循环

js 复制代码
async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}

async function async2() {
  console.log('async2');
}

console.log('script start');
setTimeout(function() {
  console.log('setTimeout');
});

async1();
console.log('script start');
new Promise(function(resolve) {
  console.log('promise1');
  resolve();
}).then(function() {
  console.log('promise2');
});
输出:
script start
async1 start
async2
script start
promise1
async1 end
promise2
setTimeout

js是一个单线程,会阻塞代码

为了防止阻塞代码,把代码分为同步和异步

同步代码交给js引擎执行(js只能是单线程)

异步代码交给宿主环境(浏览器/node,可以支持多线程)

同步代码放到执行栈,异步代码等时机成熟会放到任务队列里

执行栈执行完,会去任务队列看是否有异步任务,有就推送到执行栈执行,反复循环查看执行,这个过程就是事件循环(eventloop)

1.同步任务和异步任务

1.定时器

js 复制代码
console.log(1)
setTimeout(() => {
  console.log(2)
}, 0)
console.log(3)
输出:132

js是单线程的,同一时间只能做一件事

作为浏览器脚本语言,与它的用途有关

js主要用途是和用户互动,以及操作DOM,这决定了它只能是单线程

例如如果线程1和线程2分别是添加和删除同一个节点,执行顺序不同会导致结果的不同

所以只能先添加再删除

总不能等计时器结束才执行吧,总不能等到事件监听点击之后才执行吧

异步代码的共同点:它们都是耗时的

同步代码放到执行栈,异步代码放到宿主环境

执行栈:里的代码立即执行,并且原地等待结果

宿主环境的时间一到,就推送到任务队列

执行栈执行完了,就会看任务队列有没有异步任务需要执行

此时再把任务队列的异步函数的回调函数推送到执行栈

执行栈只要同步代码一执行完,就会反复到任务队列去看有没有异步的任务需要执行

从执行栈到任务队列反复查找的过程就叫事件循环

2.异步任务(宏任务/微任务)

js把异步任务分为宏任务和微任务

ES5之后,js引入了Promise

这样,即使不需要浏览器,js引擎自身也能发起异步任务

宏任务由宿主(浏览器、Node)发起

微任务由JS引擎发起

主要的异步任务有Promise

不过Promise本身同步,里面的then/catch的回调函数是异步的

代码示例
js 复制代码
console.log(1);
setTimeout(function () {
    console.log(2);
}, 0);

const p = new Promise((resolve, reject) => {
    console.log(3);
    resolve(1000); // 标记为成功
    console.log(4);
});

p.then(data => {
    console.log(data);
});

console.log(5);
输出:1 3 4 5 1000 2
js 复制代码
new Promise((resolve, reject) => {
  resolve(1);


  new Promise((resolve, reject) => {
    resolve(2);
  }).then(data => {
    console.log(data);
    });
}).then(data => {
  console.log(data);
});

console.log(3);
输出:3 2 1
js 复制代码
console.log(11);

setTimeout(() => {
  console.log(12);
  let p = new Promise((resolve) => {
    resolve(13);
  });
  p.then(res => {
    console.log(res);
  });
}, 0);

console.log(15);

console.log(14);
输出:11 15 14 12 13
js 复制代码
setTimeout(() => {
  console.log(1);
}, 0);

new Promise((resolve, reject) => {
  console.log(2);
  resolve('p1');
})
new Promise((resolve, reject) => {
  console.log(3);
  setTimeout(() => {
    resolve('setTimeout2');
    console.log(4);
  }, 0);
  resolve('p2');
}).then(data => {
  console.log(data);
});

setTimeout(() => {
  resolve('setTimeout1');
  console.log(5);
}, 0).then(data => {
  console.log(data);
});

console.log(6);
js 复制代码
setTimeout(() => {
  console.log(1);
}, 0);

new Promise((resolve, reject) => {
  console.log(2);
  resolve('p1');

  new Promise((resolve, reject) => {
    console.log(3);
    setTimeout(() => {
      resolve('setTimeout2');
      console.log(4);
    }, 0);
    resolve('p2');
  }).then(data => {
      console.log(data);
})

  setTimeout(() => {
      resolve('setTimeout1');
      console.log(5);
  }, 0)
}).then(data => {
    console.log(data);
});

console.log(6);

输出:2 3 6 p2 p1 1 4 5
定时器里的resolve('setTimeout2')、resolve('setTimeout1')是迷惑性的
promise里有resolve,定时器里是不执行的

async函数里的代码属于同步任务,await后面所有的代码,在函数后面的所有代码都属于微任务,等代码执行完了才去执行

js 复制代码
async function async1() {
  console.log('async1 start');
  await async2(); //await下面的代码暂时是不执行的,除非右边全部执行完了才会去执行
  console.log('async1 end');
}

async function async2() {
  console.log('async2');
}

console.log('script start');

setTimeout(function () {
  console.log('setTimeout');
}, 0);

async1();
输出:script start/async1 start/async2/async1 end/setTimeout
相关推荐
驰羽2 小时前
[GO]gin框架:ShouldBindJSON与其他常见绑定方法
开发语言·golang·gin
小宁爱Python2 小时前
Django Web 开发系列(二):视图进阶、快捷函数与请求响应处理
前端·django·sqlite
fox_2 小时前
深入理解React中的不可变性:原理、价值与实践
前端·react.js
程序员大雄学编程3 小时前
「用Python来学微积分」5. 曲线的极坐标方程
开发语言·python·微积分
Github项目推荐3 小时前
你的错误处理一团糟-是时候修复它了-🛠️
前端·后端
Code小翊3 小时前
C语言bsearch的使用
java·c语言·前端
云枫晖3 小时前
Webapck系列-初识Webpack
前端·javascript
慧一居士3 小时前
HTML5 功能介绍,使用场景,对应功能点完整使用示例
前端
海在掘金611273 小时前
告别“undefined is not a function”:TS如何让你的函数调用更安心
前端