一、异步和单线程
一.单线程和异步
a.单线程
1.JS是单线程语言,只能同时做一件事
2.浏览器和nodejs已支持JS启动进程,如Web Worker
3.JS和DOM渲染共用同一个线程,因为JS可修改DOM结构
b.异步
1.遇到等待(网络请求,定时任务)不能卡住
2.需要异步
3.回调callback函数形式
c.异步和同步的区别是什么?
1.基于JS是单线程语言
2.异步不会阻塞代码执行
3.同步会阻塞代码执行
d.前端使用异步的场景
1.网络请求,如ajax,图片加载
2.定时任务,如setTimeout
二、Promise的基本使用和原理
1. Promise Api
1.Promise.resolve() 返回异步操作成功的结果
2.Promise.reject() 返回异步操作失败的结果
3.then 执行Promise状态是成功的操作
4.catch 执行Promise状态是失败的操作
5.finally 不管Promise状态是成功或失败都执行的操作
6.Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
7.Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
2. Promise 的基本使用和原理
Promise的基本使用和原理
1.三种状态:pending,fulfilled, rejected
2.初始状态是pending
3.pending变成resolve,或者pending变为reject
4.状态变化不可逆
5.Promise 实例必须实现then这个方法
6.then()必须可以接收两个函数作为参数
7.then()返回的必须是一个Promise实例
3. 状态的表现
pending状态,不会触发then和catch
resolved状态,会触发后续的then回调函数
const p1 = Promise.resolve(100)
p1.then(data => {
console.log('data', data)
}).catch(err => {
console.error('err', err)
})
rejected状态,会触发后续的catch回调函数
const p2 = Promise.reject('err')
p2.then(data => {
console.log('data2', data)
}).catch(err => {
console.error('err2', err)
})
4. then 和 catch 改变状态
1.then正常返回resolved,里面有报错则返回rejected
const p1 = Promise.resolve().then(() => {
return 100
})
console.log('p1', p1)
p1.then(() => {
console.log('123')
})
const p2 = Promise.resolve().then(() => {
throw new Error('then error')
})
console.log('p2', p2)
p2.then(() => {
console.log('456')
}).catch(err => {
console.error('err100', err)
})
2.catch正常返回resolved,里面有报错则返回rejected
const p3 = Promise.reject('my error').catch(err => {
console.error(err)
})
console.log('p3', p3)
p3.then(() => {
console.log(100)
})
const p4 = Promise.reject('my error').catch(err => {
throw new Error('catch err')
})
console.log('p4', p4)
p4.then(() => {
console.log(200)
}).catch(() => {
console.log('some err')
})
5.遇到面试题
面试题-第一题
Promise.resolve().then(() => {
console.log(1)
}).catch(() => {
console.log(2)
}).then(() => {
console.log(3)
})
面试题-第二题
Promise.resolve().then(() => {
console.log(1)
throw new Error('erro1')
}).catch(() => {
console.log(2)
}).then(() => {
console.log(3)
})
面试题-第三题
Promise.resolve().then(() => {
console.log(1)
throw new Error('erro1')
}).catch(() => {
console.log(2)
}).catch(() => {
console.log(3)
})
6. 用Promise封装图片加载函数
function loadImg(src) {
return new Promise((resolve, reject) => {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => {
const err = new Error(`图片加载失败 ${src}`)
reject(err)
}
img.src = src
})
}
const url = 'https://cn.vuejs.org/images/logo.svg'
loadImg(url).then(img => {
console.log(img.width)
return img
}).then(img => {
console.log(img.height)
}).catch(ex => console.error(ex))
const url1 = 'https://cn.vuejs.org/images/logo.svg'
const url2 = 'https://cdn.segmentfault.com/r-de8b21ca/static/logo-b.d865fc97.svg'
loadImg(url1).then(img1 => {
console.log(img1.width)
return img1
}).then(img1 => {
console.log(img1.height)
return loadImg(url2)
}).then(img2 => {
console.log(img2.width)
return img2
}).then(img2 => {
console.log(img2.height)
}).catch(ex => console.error(ex))
7. Promise 封装 axios 请求
function get(_url, _params) {
_params = _params || {}
return new Promise((resolve, reject) => {
axios.get(_url, { _params })
.then(res => {
if (res.status === 2000) {
resolve(res.data)
}
})
.catch( error => {
reject(error)
})
})
}
8.Promise有哪些方法?他们的应用场景是什么?(all/race)
Promise.all()
1.只有`p1`、`p2`、`p3`的状态都变成`fulfilled`,`p`的状态才会变成
`fulfilled`,此时`p1`、`p2`、`p3`的返回值组成一个数组,传递给`p`的回调函数。
2.只要`p1`、`p2`、`p3`之中有一个被`rejected`,`p`的状态就变成`rejected`,
此时第一个被`reject`的实例的返回值,会传递给`p`的回调函数。
const promise1 = new Promise(resolve => {
setTimeout(() => {
resolve(1)
}, 3000)
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(2)
}, 2000)
})
const promise3 = new Promise(resolve => {
setTimeout(() => {
resolve(3)
}, 1000)
})
Promise.all([promise1, promise2, promise3]).then(v => {
console.log('then');
console.log(v, 'v');
}).catch(v => {
console.log('catch');
console.log(v, 'v')
})
当网络请求慢于2s的时候,就提示网络状态不佳
Promise.race([promise1, promise2]).then(v => {
console.log('then');
console.log(v, 'v');
}).catch(v => {
console.log('catch');
console.log('网络状态不佳')
console.log(v, 'v')
})
9.如何让Promise顺序执行?(async/await)
const promise1 = new Promise(resolve => {
setTimeout(() => {
resolve(1)
}, 3000)
})
const promise2 = new Promise((resolve) => {
setTimeout(() => {
resolve(2)
}, 2000)
})
const promise3 = new Promise(resolve => {
setTimeout(() => {
resolve(3)
}, 1000)
})
async function execute() {
await promise1.then(v => console.log(v));
await promise2.then(v => console.log(v));
await promise3.then(v => console.log(v));
}
execute()
三、请描述event loop(事件循环/事件轮询)的机制,可画图
请描述event loop(事件循环/事件轮询)的机制,可画图
1.同步代码。一行一行放在Call Stack(调用栈)执行
2.遇到异步,会先记录下,等待时机(定时器、网络请求等)
3.时机到了,就移动到Callback Queue(回调队列)
4.如Call Stack为空(即同步代码执行完)Event Loop 开始工作
5.轮询查找Callback Queue,如有则移动到Call Stack执行
6.然后继续轮询查找
a.JS是单线程的
b.异步(setTimeout, ajax等)使用回调,基于event loop
c.DOM事件也使用回调,基于event loop

四、async/await
1.异步回调callback hell
2.Promise then catch 链式调用,但也是基于回调函数
3.async/await是同步语法,彻底消灭回调函数
function loadImg(src) {
return new Promise((resolve, reject) => {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => {
const err = new Error(`图片加载失败 ${src}`)
reject(err)
}
img.src = src
})
}
const url1 = 'https://cn.vuejs.org/images/logo.svg'
const url2 = 'https://cdn.segmentfault.com/r-de8b21ca/static/logo-b.d865fc97.svg'
const res = async function(){
const img1 = await loadImg(url1)
console.log(img1.height, img1.width, 'url1')
const img2 = await loadImg(url2)
console.log(img2.height, img2.width)
}
res()
五、 async/await 和 Promise 的关系
1.async/await是消灭异步回调的终极武器
2.但和Promise并不互斥,反而,两者相铺相成
3.执行async函数,返回的是Promise对象
4.await相对于Promise的then
5.try...catch可捕获异常,代替了Promise的catch
async function fn1() {
return Promise.resolve(200)
}
const res1 = fn1()
res1.then(data => {
console.log('data', data)
})
const res2 = async function() {
const p1 = Promise.resolve(300)
const data = await p1
console.log('data', data)
}
res2()
const res3 = async function() {
const data = await 400
console.log('data', data)
}
res3()
const res4 = async function() {
const p4 = Promise.reject('err1')
try {
const res = await p4
console.log(res)
} catch(ex) {
console.error(ex)
}
}
res4()
const res5 = async function() {
const p4 = Promise.reject('err1')
const res = await p4
console.log(res)
}
res5()
面试题-第一题
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
async1()
console.log('script end')
面试题-第二题
async function fn() {
return 100
}
(async function() {
const a = fn()
const b = await fn()
})()
面试题-第三题
(async function() {
console.log('start')
const a = await 100
console.log('a', a)
const b = await Promise.resolve(200)
console.log('b', b)
const c = await Promise.reject(300)
console.log('c', c)
console.log('end')
})()
面试题-第四题
console.log(100)
setTimeout(() => {
console.log(200)
})
Promise.resolve().then(() => {
console.log(300)
})
console.log(400)
面试题-第五题
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')
}, 0)
async1()
new Promise(function(resolve) {
console.log('promise1')
resolve()
}).then(function() {
console.log('promise2')
})
console.log('script end')
六、宏任务 macroTask 和微任务 microTask
宏任务macroTask和微任务microTask
a.什么是宏任务,什么是微任务
1.宏任务:setTimeout, setTnterval, Ajax, DOM事件
2.微任务:Promise async/await
3.微任务执行时机比宏任务要早(先记住)
b.event loop 和 DOM渲染
1.每次Call Stack清空(即每次轮询结束),即同步任务执行完
2.都是DOM重新渲染的机会,DOM结构如有改变则重新渲染
3.然后再去触发下一次Event Loop
c.微任务和宏任务的区别
1.宏任务:DOM渲染后触发,如setTimeout
2.微任务:DOM渲染前触发,如Promise
3.微任务是ES6语法规定的
4.宏任务是由浏览器规定的
d.微任务、宏任务和DOM渲染,在event loop的过程
