进程线程
- 进程:CPU在指令和保存上下文对象需要的时间 (比如:手机打开微信,系统在执行打开指令到加载微信上下文环境,直到彻底关闭微信之前的这段时间,都是一个进程)
- 线程:是进程中一个更小的一个单位,指的是执行一段指令所需的时间 (比如打开微信聊天界面,就需要一个渲染线程,同时获取最新消息,需要一个网路线程)
浏览器新开一个tab页面就是一个新的进程,这个进程中有很多线程相互配合工作,最后展示页面给到用户 这个过程涉及到的线程有:
- http 线程
- js引擎线程
- 渲染线程
线程之间通常都可以同时工作,但是只有js引擎线程和渲染线程是互斥的,但是其他线程之间是可以同时工作
异步
- v8在执行js代码时默认只开启一个线程工作,(js是单线程的 是指v8在执行一份js代码时,只会开一个线程执行),所以考虑到执行效率,v8会先执行同步代码,遇到异步代码,会将异步代码存放到任务队列(微任务队列、宏任务队列),等到js引擎空闲时,再从任务队列中取出异步代码,执行异步代码
跳过异步先执行同步
EventLoop
- js代码中有同步和异步之分,异步还被分为宏任务和微任务
微任务:promise.then , process.nextTick, MutationObserver(.then是微任务)
宏任务:setTimeout, setInterval, ajax, setImmediate(已废弃), I/O,
UI rendering(页面渲染)
- 执行顺序:
1.先执行同步代码(这属于宏任务),这个过程中遇到异步,就存入任务队列(微任务队列、宏任务队列)
2.同步执行完毕后,先执行微任务队列中的代码
3.微任务全部执行完毕后,有需要的情况下渲染页面
4.渲染完毕后,执行宏任务队列中的代码(开启下一次事件循环)
console.log(1);
new Promise((resolve) => {
console.log(2);
resolve();
})
.then(() => {
console.log(3);
setTimeout(() => {
console.log(4);
}, 0);
});
setTimeout(() => {
console.log(5);
setTimeout(() => {
console.log(6);
}, 0);
}, 0);
console.log(7);
具体实现过程:
先执行同步代码,1 ,2执行完,遇到异步代码.then将异步代码放入微任务队列,继续执行遇到setTimeout放入宏队列代码,最后继续执行同步代码3,执行完同步代码,此时微任务的队列中微任务出队列,执行微任务,执行4后,继续执行遇到宏任务,加入宏任务队列,此时微任务执行完毕,查看是否需要渲染,不需要,执行宏任务,执行5,6,7,最后打印结果为1273546
async和await
function a() {
setTimeout(() => {
console.log("a");
}, 1000);
}
function b() {
console.log("b");
}
function foo() {
a();
b();
}
foo();
如果要执行以上代码,让a先执行完,可以用回调的形式
也可以使用.then的形式
function a() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("a");
resolve();
}, 1000);
});
}
function b() {
console.log("b");
}
function foo() {
a().then(() => {
b();
});
}
foo();
但是这样依然看着很繁琐,于是便有了 async 和 await的出现
es7新加 async是语法糖,是return new Promise的封装,await相当于.then()
async写法:
注意 语法规定await必须被包裹在async里面,所以我们每次使用时都必须多加一个外层async的外层函数, 于是上面的代码就可以写成
function a() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("a");
resolve();
}, 1000);
});
}
function b() {
console.log("b");
}
async function foo() {
await a().then(() => {
b();
});
}
foo();
await
-
会将后续的代码挤入微任务队列(后续指的是下一行及以下的代码)
-
浏览器对 await的执行时间提前了(await 后面的代码当作同步来看待,是await 紧挨着的代码)
console.log('script start');
async function async1() {
await async2() //
console.log('async1 end');
}
async function async2() {
console.log('async2 end');
}
async1()
setTimeout(() => {
console.log('setTimeout');
}, 0)
new Promise((resolve, reject) => {
console.log('promise');
resolve()
})
.then(() => {
console.log('then1');
})
.then(() => {
console.log('then2');
});
console.log('script end');
按事件循环四部曲: 先执行同步代码1,然后执行第9行时,遇到await修饰的async2(),会先执行async2() 就是执行2,await修饰代码的后续代码进入微任务队列,执行同步3,触发。then()执行 .then(log(then1)).then(log(then2))进入微任务队列,执行同步4,同步执行完毕,执行微任务队列,5,6,微任务执行完毕,查看是否需要渲染,不需要,执行宏任务队列,7,要想await修饰的先执行,必须确保修饰的函数调用的函数体是async修饰或则返回了new promise。
如有错误欢迎指正,欢迎友友们点赞评论