一:单线程和异步
- JS是单线程语言,只能同时做一件事
- 浏览器和nodejs已支持JS启动进程,如Web Worker
- JS和Dom渲染共用一个线程(涉及到后面的event loop机制的宏/微任务的先后)
进程(process):系统中正在运行的一个应用程序;程序一旦运行就成为了一个进程
线程(thread):线程时进程的最小执行单位,一个进程中可以只有一个线程,这称为单线程,也可以存在多个线程并行执行不同的任务,这称为多线程
- 基于JS是单线程语言,但是同步会阻塞代码执行,异步不会阻塞代码执行(是以回调callback函数形式),故在JS的应用中引入了异步的概念;前端常见异步应用场景: 1)网络请求,,如ajax加载图片 2)定时任务,如setTimeout
手写一个Promise加载一张图片
function loadImg(src) {
const p = new Promise(resolve, reject) {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => {
reject(new Error('图片加载失败'))
}
// 一旦赋值触发上面的img.onload函数
img.src = src
}
return p
2: event loop(事件循环/事件轮询)机制
event-loop 是js异步回调的是实现原理:
- 同步代码一行一行放到执行栈(call stack)中执行
- 遇到异步会先“记录”下,等到异步任务有了结果(定时任务触发或是网络请求完成,就会在回调任务队列(callback queue)中放置一个事件;
- 一旦执行栈(call stack)中所有同步任务执行完毕,【它会先尝试DOM渲染(这个触及到了宏/微任务的概念,在这可忽略提及方面)】,
- 会触发event loop会开始执行,不断轮询查找回调任务队列(callback queue),如果有就移动到执行栈(call stack) 中执行,然后继续轮询查找
异步(setTimeout,ajax等)使用回调,基于event loop机制,而Dom事件(click事件)也是基于event loop使用回调
关于Promise的基础知识可以看笔记ECMAScript 6 入门之Promise
关于ajax的相关知识可以看笔记关于Ajax
关于async await 和Promise的结合应用可以看笔记ECMAScript 6 入门之async函数
Promise 中 then 和 cache 对状态的影响:
- then 正常返回 resolved 状态的 Promise,里面有报错则返回 rejected 状态的 Promise
- catch 正常返回 resoved 状态的 Promise,里面有报错则返回rejected状态的 Promise
Promise.resolve().then(() => {
console.log(1)
}).cache(()=> {
cosole.log(2)
}).then(() => {
console.log(3)
})
// 输出1 3,并且最终返回的是resolved状态饿Promise
Promise.resolve().then(() => {
console.log(1)
throw new Error('error1)
}).cache(()=> {
cosole.log(2)
}).then(() => {
console.log(3)
})
// 输出1 2 3,并且最终返回的是resolved状态的Prommise
Promise.resolve().then(() => {
console.log(1)
throw new Error('error1)
}).cache(()=> {
cosole.log(2)
}).cache(() => {
console.log(3)
})
// 输出1 2,并且最终返回的是resolved状态的Prommise
插入:关于for-of的应用:
需要知道:
- forEach是常规的同步遍历
- for、for…in…、for…of… 常用于异步的遍历
function muti(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num*num)
}, 1000)
})
}
const nums = [1,2,3]
// 同步遍历异步方法------->一瞬间arr.forEach执行完毕,几近同时放置了三个定时为1s的计时器,故1s后,同时输出1,4,9
arr.forEach(async e => {
const res = await muti(e)
console.log(res)
})
// 按顺序执行异步,比如第二次的异步请求数据需要等待第一次异步请求完毕之后再触发
// 使用for of遍历数组的每一项,不是下标哦!!(for in 既可以遍历对象也可以遍历数组)
// 会每隔1s输出对应数字
for(let i of nums) {
const res = await muti()
console.log(res)
}
// for(let i = 0 ;i<nums.length;i++) 也可!!
3:宏任务和微任务
1:二者介绍
-
宏任务:setTimeout,setInterval,Ajax, DOM事件
-
微任务: Promise async/await
-
二者区别 :微任务执行时机比宏任务要早
- 宏任务:DOM渲染后触发,如setTimeout - 微任务:DOM渲染前触发,如Promise
2: 微任务执行时机比宏任务要早原因:
微任务是ES6语法规定,宏任务是浏览器规定的,所以二者其实存放的地方不一样;在之前说的event loop中加入DOM的渲染机制及宏任务/微任务的概念,系统的解释了