最近参加拉勾教育大前端高薪训练营,开始对前端知识体系进行一个系统的扩展跟学习,通过每天定期的学习,对一些不常使用的知识点进行了了解和补充,同时对已经使用过的知识点温故而知新
在此记录学习笔记,并根据学习进度定时跟新
单线程JavaScript
- 为了避免多线程同步(操作DOM)问题
- JS执行环境中,负责执行代码的线程只有一个
- 优点:
- 安全
- 简单
- 缺点:
- 耗时任务阻塞执行
同步模式
同步代码依次加入调入栈,执行完成后从调用栈移除
异步模式
-
不会等待任务结束再执行,开启后立即执行下一个任务
-
后续逻辑通过回调函数定义
-
使单线程JavaScript能够执行大量耗时任务
-
缺点:代码执行顺序混乱
-
JavaScript是单线程,但浏览器并不是单线程
异步任务交给异步线程执行,执行完成后,将回调逻辑加入消息队列,当调用栈中的任务执行完成后,事件循环将消息队列中的第一个任务加入调用栈执行,开始下一轮事件循环
Promise
由CommonJS社区提出了Promise的规范,在ES2015中被标准化
-
Promise有三种状态
- pending
- fulfilled
- 调用resolve
- rejected
- 调用reject
-
Promise的状态一旦确定后就不能再被修改
-
使用案例
-
模拟实现Promise版ajax
function ajax(url) { return new Promise(function(resolve, reject) { const xhr = new XMLHttpRequest() xhr.open('GET', url) xhr.responseType = 'json' xhr.onload = function() { if (this.status === 200) { resolve(this.response) } else { reject(new Error(this.statusText)) } } xhr.send() }) }
-
-
常见错误
- 嵌套调用
-
链式调用
- then方法会返回一个全新的Promise对象
- then方法为之前返回的Promise对象注册回调
- 前面then方法中回到函数的的返回值会作为后面then方法回到的参数传入
- 如果回调中返回的是Promise,那后面的then的回调会等待Promise结束
- 如果传入then的参数非回调函数,这个then会被忽略执行(跳过)
-
异常处理
- 两种方式
- then方法的第二个参数回调函数中捕获
- catch方法回调函数中捕获
- 差异
- then方法的第二个参数回调函数可以捕获then之前的Promise产生的异常
- cache方法可以捕获前面Promise以及then中产生的异常,实际为前面then返回的新Promise,只不过异常通过then的链式调用传递了
- 全局异常捕获
- web环境window.addEventListener注册unhandledrejection事件
- node环境process.on注册unHandledRejection事件
- 不推荐采用全局捕获的方式处理异常,而应该在代码中明确捕获异常并处理
- 两种方式
-
静态方法
- Promise.resolve()
- 如果传入的是普通的值,返回一个已经resolve的Promise对象,Promise.reslve(value)等同于new Promise(resolve => resolve(value))
- 如果传入的是Promise对象,则直接返回传入的Promise对象本身,使用===比较相等
- 如果传入的是thenable对象(实现了then方法并带有resolve,reject回调函数参数的对象),则转化为相应then方法的Promsie对象,这个特性可以用来转化第三方库实现的Promise对象为标准Promise对象
- Promise.reject()
- 无论传入什么值,都会作为reject的原因传入异常捕获回调
- Promise.resolve()
-
并行执行
- Promise.all()
- 接收一个Promise对象数组作为参数,返回一个Promise对象
- 数组中的所有Promise都被resolve后,将所有Promsie对象resolve返回的数组传入then的回调
- 如果有Promise被reject,则返回第一个被reject的Promise的状态传入then或cache的回调
- 接收一个Promise对象数组作为参数,返回一个Promise对象
- Promise.race()
- 接收一个Promise对象数组作为参数,数组中的任意Promise状态发生变化,返回一个Promise对象,将第一个发生状态变化的Promise状态传入相应的回调
- Promise.all()
-
执行时序
- Promise的回调作为微任务,其他还有node的process.nextTick,MutationObserver
- setTimeout、setInterval等作为宏任务
Generator异步方案
ES2015引入,生成器函数,使异步调用操作扁平化
-
函数名前加*为生成器函数,调用生成起函数返回一个生成器对象
-
函数中通过yield关键字,可以暂停函数执行
-
生成器对象通过调用next()方法,执行到下一个yield之前的代码,并返回一个对象,包含value和done两个属性
- value:yield之后的表达式的值
- done:表示生成器是是否执行完成
-
调用next()方法传入参数,则参数值会作为yield的返回值,传递给yield左边的变量
-
调用throw()方法,会抛出异常,可以由生成器函数内部捕获,也可以由函数外部捕获
-
生成器自动执行函数(执行器)co模拟实现
function co(generator) { function handleResult(result) { if(result.value.done) return result.value.then(data => { handleResult(generator.next(data)) }, error => generator.throw(error)) } handleResult(generator.next()) }
async/await
ES2017引入,Generator的语法糖,异步操作自动执行,更加语义化
- async函数返回一个Promise对象
- 将await之前的代码放入Promise.resolve()
- 将await之后的代码放入then
- 如果执行异常,则放入Promise.reject()
- await之后是一个Promise对象
- 则Promise.resolve()回调的参数值作为await表达式的值
- 抛出Promise.reject()的异常
- await之后是一个常量,则将值作为参数,返回一个Promise.resolve()
网友评论