内容概要
- 同步模式与异步模式
- 事件循环与消息队列
- 异步编程的几种方式
- Promise异步方案、宏任务/微任务队列
- Generator异步方案、Async/Await语法糖
同步模式 Synchronous
回调函数
- 所有异步编程方案的根基
- 回调函数可以理解为一件你想要做的事情
Promise
- 一种更优的异步编程解决方案
- 链式调用
基本用法
const promise = new Promise((resolve, reject) => {
// 这里用于兑现承诺
// resolve(100) // 承诺达成
reject(new Error('promise rejected')) // 承诺失败
})
promise.then((value) => {
console.log('resolved', value)
},(error) => {
console.log('rejected', error)
})
console.log('end')
// end
// promise rejected
// 说明promise的then 和 失败回调都被放进异步队列
链式调用
- Promise对象的then方法回返回一个全新的Promise 对象
- 后面的then方法就是在为上一个then返回的Promise注册回调
- 前面then方法中回调函数的返回值会作为后面then方法回调的参数
- 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束 ```javascript ajax(‘/api/uses.json’) .then(() => { console.log(111111) }) .then(() => { console.log(22222) }) .then(() => { console.log(33333) }) .then(() => { console.log(44444) return ‘foo’ }) .then((value) => { console.log(55555) console.log(value) })
/ 11111 22222 33333 44444 55555 foo /
**异常处理**
- 在代码中捕获每一个可能出现的异常
- catch方法捕获异常
**Promise.all 并行执行**
- ** **等待所有任务结束,才会结束
```javascript
var promise = new Promise.all([
ajax('/api/user.json'),
ajax('/api/user2.json')
])
promise.then((values) => {
console.log(values) // 返回数组
}).catch((error) => {
console.log(error)
})
Promise.race
- 只会等待第一个结束的任务
执行时序
js引擎是单线程的
- 同步任务:所有在主线程上排队执行的任务都叫同步任务,只有前一个任务执行完毕,才会执行下一个任务
- 异步任务:不进入主线程而进入“任务队列”执行的任务,只有等主线程的同步任务都执行完,任务队列里的异步任务才会进入主线程执行。
- 异步任务包括宏任务和微任务
- 宏任务(macro-task): script、setInterval、setTimeout、
- 微任务(micro-task): Promise、process.nextTick
- Promise 不全是异步任务,Promise 里面的代码是同步的,执行resolve或reject回调的时候,会把then或catch 回调放异步任务中的微任务队列
- 异步任务包括宏任务和微任务
- JS 引擎的运行机制
- 所有的同步任务都在主线程上执行,形成一个执行栈
- 主线程之外还一个任务队列,当异步任务有了运行结果,就会在任务队列放置一个事件
- 当执行栈里的所有同步任务执行完毕,系统就会去读取任务队列,将事件对应的异步任务放到执行栈中继续执行
- 主线程不断的重复执行上面的第三步
- 执行顺序
- 执行栈中从上往下一次执行,同步任务直接执行,异步任务会被放到任务队列中
- 当所有的同步任务执行完毕,开始执行所有的异步任务(也就是任务队列里的任务)
- 首先会执行任务队列里所有的微任务
- 然后执行一个宏任务
- 然后再执行完所有的微任务
- 执行宏任务、所有的微任务… 以此类推,知道所有的任务执行完毕
- 以上c到f 这个循环便是事件循环 event loop
- 事件循环是js 实现异步的一种方法,也是javaScript 的运行机制
宏任务和微任务都是实现异步的方式
Generator 生成器函数
- 函数名前加星号 * ,调用时函数不会立即执行,而是生成一个函数生成器的对象
- 通过对象.next() 获取执行结果
- 通过对象.throw() 抛出异常
- yield 可以暂停生成器的执行
function * main() {
try {
const users = yield ajax('/api/uses.json')
console.log(1)
const posts = yield ajax('/api/posts.json')
console.log(2)
const uses1 = yield ajax('/api/uses1.json')
console.log(3)
} catch(e) {
console.log(e)
}
}
function co(generator) {
const g = generator()
function handleResult (result) {
if(result.done) {
result.value.then(data => {
handleResult(g.next(data))
}, error => {
g.throw(error)
})
}
}
handleResult(g.next())
}
co(main);
/*
1
2
3
*/
Async/ Await 语法糖
- 语言层面的一步编程标准
目前主流用法 ```javascript async function main() { try {
const users = await ajax(‘/api/uses.json’) console.log(1)
const posts = await ajax(‘/api/posts.json’) console.log(2)
const uses1 = await ajax(‘/api/uses1.json’) console.log(3)
} catch(e) { console.log(e) } }
main()
/ 1 2 3 / ```