JS 异步编程
JavaScript异步编程
单线程: JS执行环境中负责执行代码的线程只有一个
优点: 更安全更简单
缺点: 耗时任务阻塞
同步模式—调用栈(Call stack)排队执行
异步模式
不会去等待这个任务的结束才开始下一个任务
开启过后立即往后执行下一个任务
后续逻辑一般会通过回调函数的方式定义
消息队列(Queue)和事件循环(Event loop)
运行环境提供的API是以同步或异步模式的方式工作
EventLoop 是一种循环机制 ,不断去轮询一些队列 ,从中找到 需要执行的任务并按顺序执行的一个执行模型。
消息队列 是用来存放宏任务的队列, 比如定时器时间到了, 定时间内传入的方法引用会存到该队列, ajax回调之后的执行方法也会存到该队列。
一开始整个脚本作为一个宏任务执行。执行过程中同步代码直接执行,宏任务等待时间到达或者成功后,将方法的回调放入宏任务队列中,微任务进入微任务队列。
当前主线程的宏任务执行完出队,检查并清空微任务队列。接着执行浏览器 UI 线程的渲染工作,检查web worker 任务,有则执行。
然后再取出一个宏任务执行。以此循环…
宏任务可以理解为每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。
浏览器为了让 JS 内部宏任务 与 DOM 操作能够有序的执行,会在一个宏任务执行结束后,在下一个宏任务执行开始前,对页面进行重新渲染。
宏任务包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、MessageChannel 等
微任务可以理解是在当前任务执行结束后需要立即执行的任务。也就是说,在当前任务后,在渲染之前,执行清空微任务。
所以它的响应速度相比宏任务会更快,因为无需等待 UI 渲染。
微任务包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)等
Promise
三个状态 Pending Fulfilled-onFulfilled Rejected-onRejected
状态更改之后不可修改
promise 基本用法
const promise = new Promise(function(resolve, reject){
// foo()
// throw new Errow(‘error’)
resolve(100)
// reject(new Error("promise rejected"))
})
// promise.then(function(value){
// console.log(‘resolved’, value)
// }, function(error){
// console.log(‘rejected’, error)
// })
// console.log(‘end’)
Promise 常见误区—回调嵌套
Promise 链式调用
then方法会返回一个全新的Promise对象
后面的then方法就是在为上一个then返回的Promise注册回调
前面then方法中的回调函数的返回值会作为后面then方法回调的参数
如果回调中返回的是Promise, 那么后面then方法的回调会等待它的结束
let promise2 = promise.then(function(value){
console.log(‘resolved’, value)
}, function(error){
console.log(‘rejected’, error)
}) .then(function(value){
console.log(‘resolved’, value)
}, function(error){
console.log(‘rejected’, error)
}) .then(function(value){
console.log(‘resolved’, value)
}, function(error){
console.log(‘rejected’, error)
})
console.log(promise2 === promise)
promise.then(function(value){
console.log(‘resolved’, value)
}).catch(error => {
console.log(“error”, error)
})
Promise 异常处理
Promise实例的catch方法 then方法中的失败回调
区别: (1)then注册失败回调只能捕获到前一个promise的异常
(2)catch是给整个Promise链条注册的失败回调
Promise 静态方法
resolve() reject()
Promise 静态方法 Promise.resolve() Promise.reject()
三种是等价的 有thenable接口的函数
Promise.resolve(‘f00’).then( value => {
console.log(‘resolve’, value)
})
Promise.resolve({
then: (onFulfilled, onRejected) => {
onFulfilled(‘f00’)
}
}).then(value => {
console.log(value)
})
new Promise((resolve, reject) => {
resolve(‘f00’)
}).then(value => {
console.log(‘new’, value)
})
Promise.reject(new Error(‘rejected’)).catch(error => {
console.log(‘error’, error)
})
Promise 并行执行
all()方法 race()方法
Promise 执行时序 / 宏任务 微任务
微任务: 提高整体的响应能力
Promise 执行时序 / 宏任务 微任务
console.log(‘global start’)
setTimeout(()=>{
console.log(‘setTimeout1’)
}, 1000)
setTimeout(()=>{
console.log(‘setTimeout’)
}, 100)
Promise.resolve().then(()=>{
console.log(‘promise’)
}).then(()=>{
console.log(‘promise1’)
})
console.log(‘global end’)
Generator异步方案
//Generator异步方案
function *foo(){
console.log(“start”)
try{
const res = yield ‘foo’
console.log(res, ‘res’)
}catch(e){
console.log(e, ‘e’)
}
}
const generator = foo()
const result = generator.next()
console.log(result, ‘result’)
generator.next(‘bar’)
generator.throw(new Error(‘Generator Error’))
//管理异步流程 体验Generator 函数异步方案
function *main(){
try{
const users = yield promise
console.log(‘users’, users)
const posts = yield Promise.resolve(200)
console.log(posts, 'posts')
}catch(e){
console.log(e)
}
}
const g = main()
const result = g.next()
result.value.then(data => {
const result2 = g.next(data)
if(result2.done) return
result2.value.then(data => {
g.next(data)
})
})
//递归执行Generator函数
const g = main()
function handleResult (result){
if(result.done) return
result.value.then(data => {
handleResult(g.next(data))
}, error => {
g.throw(error)
})
}
handleResult(g.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(main)
Async/ Await 语法糖 语言层面的异步编程标准
async function mainSync(){
try{
const users = await promise
console.log(‘users’, users)
const posts = await Promise.resolve(200)
console.log(posts, 'posts')
}catch(e){
console.log(e)
}
}
const mains = mainSync()
mains.then(()=>{
console.log(‘all completed’)
})