实现思路
- 你需要提供暂停执行的能力
- 你需要接收
resolve的返回值
基于上述要求,可以想到生成器来实现此功能
生成器的简单使用
首先需要用 * 关键字定义生成器
当执行时,遇到yield关键字会停止执行,并返回值
function* generator() {
console.log('start...')
const a = yield 1
console.log('next函数返回的字符串', a)
}
那么如何执行呢?
// 返回一个生成器对象
const g = generator()
/**
* 第一次调用`next` 会开始迭代 遇到`yield`关键字停止 并返回一个对象
* `value`代表值 done标记是否迭代完成
*/
const r1 = g.next()
console.log('第一次调用next', r1, '\n')
调用函数得到生成器,然后用next函数即可迭代
来看看结果
start...
第一次调用next { value: 1, done: false }
他遇到yield关键字会停止执行,并返回值
那么我们怎么传递值呢
- next函数也能传递参数,这个参数可以在生成器里接收
ok,生成器的简单使用就到这了,接下来实现类似async & await
这里调用的公开免费的接口
实现方式就是递归,如果你用while循环会阻塞js
判断Promise最好别用instanceof,因为babel降级打包后,你这判断就不行了
接下来大家想怎么封装都行
// 生成器模拟async
run()
function* generator() {
const initVal = yield fetch('https://v.api.aa1.cn/api/yiyan/index.php'),
// `initVal`的值 是`next`传递过来的
res = yield initVal.text()
console.log(initVal)
console.log(res)
}
function run() {
const g = generator()
// 获取生成器的第一个`yield`值
let res = g.next()
_runTask()
function _runTask() {
if (res.done) return
if (isPromise(res.value)) {
res.value.then(data => {
// `next`接受的参数将传递到`yield`的结果
res = g.next(data)
// `_runTask`不能统一放在最底下 会导致内存溢出 因为then是微任务
_runTask()
}).catch(err => {
g.throw(err)
})
}
else {
res = g.next(res.value)
_runTask()
}
}
}
function isPromise(target) {
return typeof target === 'object' && typeof target?.then === 'function'
}
打印结果