对于解决异步的诸多方式,只是在处理异步问题上更加直观,并没有改变js是单线程语言,以及event loop的运行机制
promise
这里不会具体讲promise的用法,只记录自己感觉重要的地方
1. 注意事项
1.1 使用promise封装异步函数的时候,resolve和reject是在回调函数里面执行的。
1.2 当一个promise对象返回一个promise对象时,后面的then会作为这个返回的promise对象的第一个then处理。看代码:
promise.then(res => {
console.log(res)
return new Promise((resolve,reject) => {...})
}).then(res => {
// 这个res就是上一个then中返回的promise对象的resolve的值
// ...
})
2. 重要的API
2.1 Promise.all:将所有指定的promise都执行完,再进行下一步操作。看代码:
// promise1,promise2是传入的promise对象,是以数组的形式
Promise.all([promise1,promise2]).then(res => {
// res是一个数组,按顺序包含传入promise对象的resolve值
console.log(res[0])
console.log(res[1])
})
2.2 Promise.race:对于指定的promise对象,只要其中有一个完成了,就执行下一步。看代码:
Promise.race([promise3,promise4]).then(res => {
// res是最先完成的promise对象的resolve值
console.log(res)
})
2.3 Promise.resolve:将thenable对象转换为Promise对象,看代码:
// 什么是 thenable 对象呢?
const thenable = {
// 就是拥有 then 属性,且属性值是如下格式的函数的对象
then: (resolve,reject) => {
if (success) {
resolve(...)
} else {
reject(...)
}
}
}
// 变为promise对象
let thenPromise = Promise.resolve(thenable)
thenPromise.then(res => {...})
3. 所遵循的Promise/A+规范
这是由 CommonJS 组织制定的异步模式编程规范,promise功能的实现就是根据它来实现的
3.1 一个promise对象只有三种状态:等待pending、fulfilled已完成、已失败rejected。状态的转换只能是:pending ---> fulfilled / pending ---> rejected
3.2 then必须返回一个promise对象(这样才能实现链式调用啊!),接受两个参数,第一个是成功时的回调,第二个是失败时的回调(对于失败的回调不常用,一般用catch代替)
Generator
其实Generator并不是用来处理异步问题的,只不过使其与异步产生关联而已
1. Generator简介
1.1 Generator函数执行时,并不是立即执行函数内部的代码,而是返回一个对象(iterator对象)
1.2 执行过程是:调用next方法,会一直执行下去,直到遇到yield或者return,然后执行yield或者return后面的表达式,并且都有返回值:对于遇到yield是{value: ..., done: false},对于return是{value: ..., done: true}
2. Iterator遍历器对象
2.1 Iterator对象是一个指针对象,实现类似于单项链表的数据结构,通过next()将指针指向下一个节点
2.2 具有[Symbol.iterator]属性的对象可以生成iterator对象(见如下代码),从而可以使用for...of或者next()方法取值。原生具有[Symbol.iterator]属性的数据结构有:Array、like-Array(类数组对象)、Set、Map
let arr = [1,2,3]
// 生成iterator对象
// 可以看出对象[Symbol.iterator]属性返回的是一个函数
let iterArr = arr[Symbol.iterator]()
3. Generator注意事项
3.1 yield*后可跟一个Generator对象,并且会把它其中的yield按照规则来一步一步执行。当有多个Generator串联使用的时候,可以使用yield*
4. Thunk函数
4.1 只有一个参数的函数,而且这个参数是一个callback函数,这样的函数就是Thunk函数。看代码:
// 这是一个读取文件的函数,有三个参数
function readFile(filename,'utf-8',(err,data) => {...})
// Thunk化
const thunk = function(filename,codeType) {
return function(callback) {
readFile(path,codeType,callback)
}
}
// readFileThunk就是一个Thunk函数
const readFileThunk = thunk('test.json','utf-8')
5. 结合Thunk函数和Generator函数
上面说过Generator函数本身与异步没啥关系,但是要是将Thunk函数与Generator结合起来,就可以用来处理异步了,传入Thunk函数的callback,正好可以作为异步函数的回调
1. 手动执行,看代码:
function* G() {
const res = yield thunk('test.json','utf-8')
console.log('res: ',res)
}
const g = G()
g.next().value((err,data) => {
g.next(data)
})
2. 自动执行,看代码:
// 上面只是进行一个thunk函数的操作,若遇到多个,那又要嵌套着写,很麻烦
// 于是自执行函数出现了
function autoGenerator(G) {
// 生成iterator对象
const g = G()
function next(err,data) {
const res = g.next(data)
if (res.done) {
// 如果执行完就return
return
}
res.value(next)
}
// 先自执行一次,启动iterator
next()
}
async-await
Generator的语法糖,更加易读!
1. function* ---> async function、yield ---> await。看代码:
async function asyncFun() {
const res1 = await new Promise(...)
const res2 = await new Promise(...)
console.log('res1: ',res1)
console.log('res2: ',res2)
return 'done'
}
2. async函数返回promise,then后取到的值就是done