前言
由于js涉及dom交互,如果多线程会出现很复杂当线程同步问题,故js是单线程模式,单线程模式指执行代码当线程只有一个,故每次只能执行一个任务
单线程当优点为简单,安全,缺点为耗时任务会阻塞代码运行,出现白屏假死等影响体验的现象
故为了解决阻塞问题,js将任务的执行分为同步和异步两种模式
同步模式
指代码中任务依次执行,后一个任务必须等前一个任务执行完毕才会执行,任务等执行顺序与代码的编写顺序一致,大部分任务均为同步执行
当代码加载进来后,会由自执行函数包裹所有代码,按照从上倒下,先把第一行放到调用栈,当代码执行完毕,弹出代码,再执行下一行代码,知道都执行完毕
异步模式
不会等待任务执行完毕,才去执行下一任务,开启以后就会执行下一个任务,后续的处理逻辑会通过回调函数方式处理
在主线程外开辟新的线程,在不阻塞主线程代码大情况下,用于处理一些耗时或计算量大的任务,当异步结束后,把回调函数加入到消息队列中,等待事件循环的调用
EventLoop
事件循环会监听调用栈和队列,在调用栈空了后,事件循环会从队列中拿出第一个任务,放到调用栈中执行,执行完毕后,再拿出下一个任务,依次循环
消息队列
消息队列是存储待执行的异步回调函数,并供事件循环调用当场所,当异步代码触发回调函数时,会把此函数放在队列末尾,事件循环每次在队列当最前方取出函数去执行
宏任务与微任务
微任务有js的Promise和nodejs的process.nexttick等
宏任务有setTimeout,setInterval,js主代码等
宏任务和微任务是相对于异步代码的,在事件循环时,当微任务队列中存在任务,那么会先调用所有微任务,全部执行完毕,再去调用第一个宏任务,依次循环
异步模式执行步骤
console.log('begin')
setTimeout(function timer1 () {
console.log('timer1')
}, 1800)
console.log('end')
上方简单的异步代码,首先加载完所有代码后,会把代码放入一个自执行函数并把第一行同步代码压入调用栈,执行完毕后打印begin,然后把定时器压入调用栈,会开启一个线程用于计时,然后推出,再把end打印压入调用栈,打印end,再推出,执行完毕,调用栈为空
当计时到1.8s时,会把定时器的回调函数放到消息队列,事件循环监听到队列变更后,在调用栈为空时,会把队列的第一个推入调用栈(如果此时有微任务,会执行完所有微任务再执行此操作),执行定时器的回调函数,打印timer1
Promise
异步编程的根基是回调函数,而传统的回调函数嵌套写法,很难维护与阅读,promise可以使异步编程更可维护与阅读
new Promise(function (resolve, reject) {
// 同步执行此函数体
setTimeout(() => resolve(1))
}).then((v) => {
console.log(v); // 1
});
状态有fulFilled(成功,对应resolve,执行then的第一个参数),rejected(失败,对应rejected,执行catch回调或then的第二个参数)
Promise.all()
参数为Promise对象组成的数组,返回新的Promise,当数组中所有的Promise的状态均为fulFilled,执行then回调,参数为所有Promise的返回值组成的数组,此数组与传入数组一一对应,否则执行catch
Promise.race()
参数为Promise对象组成的数组,返回新的Promise,当数组中有一个任务结束,则直接按照该任务的状态返回
Promise.resolve()
快速把值转化为Promise对象,并执行then的第一个参数,如传入Promise对象,会直接返回
Promise.reject()
快速把值转化为Promise对象,并执行then的第二个参数,如传入Promise对象,会直接返回
Promise.finally()
参数为函数,返回值为Promise对象,不论成功或失败均会调用,并且所传函数调用时没有参数,会把当前Promise的成功或失败的值,传递给返回的新的Promise对象
Generator
使用*和yield关键字,当调用函数时,不会直接执行,而是会返回Generator对象,当调用对象当next方法时,才会执行,并且遇到yield关键字会停止执行,直到再次调用next方法
function * foo () {
const res = yield 'foo';
return res;
}
const generator = foo()
const result = generator.next(); // foo
因为每次均须手动调用next方法,所以需要一个执行器去自动执行所有next方法
function co (generator) {
const g = generator()
function handleResult (result) {
if (result.done) return // 生成器函数结束
result.value.then(data => {
handleResult(g.next(data))
}, error => {
g.throw(error)
})
}
handleResult(g.next())
}
co(foo)
async await
async await是generator的语法糖,可不用自己调用自己封装执行器,看起来更像同步代码
async function main () {
const users = await ajax('/api/users.json')
const posts = await ajax('/api/posts.json')
const urls = await ajax('/api/urls.json')
}