南京网站制作链接,全网推广平台有哪些,电子商务专业介绍,wordpress怎么弄垂直分类为什么要引入async/await操作符#xff1f;
对于js的异步编程场景#xff0c;无论是使用xhr回调还是promise回调#xff0c;当异步操作过多并且每个动作之间存在依赖关系#xff08;即需要串行执行#xff09;时#xff0c;代码的可读性和维护性会变得很差。async/await…为什么要引入async/await操作符
对于js的异步编程场景无论是使用xhr回调还是promise回调当异步操作过多并且每个动作之间存在依赖关系即需要串行执行时代码的可读性和维护性会变得很差。async/await以同步代码的形式很好地解决了这个问题。
因为async/await的底层实现使用generator和promise所以首先要了解generator的原理。
生成器函数generator
function* genDemo() {console.log(开始执行第一段)yield generator 2console.log(开始执行第二段)yield generator 2console.log(开始执行第三段)yield generator 2console.log(执行结束)return generator 2
}console.log(main 0)
let gen genDemo()
console.log(gen.next().value)
console.log(main 1)
console.log(gen.next().value)
console.log(main 2)
console.log(gen.next().value)
console.log(main 3)
console.log(gen.next().value)
console.log(main 4)带*号的函数就叫生成器函数是可以暂定执行和恢复执行的。
在执行过程中如果遇到yield关键字函数会返回关键字后面的内容给外部然后暂停执行。
外部可以使用next方法来恢复执行该函数。
v8是如何实现函数的执行和恢复的呢这里需要引入协程的概念。
协程
协程是一种比线程更轻量级的存在可以理解为是在线程上运行的任务。一个线程可以存在多个协程但同时只能执行一个协程。如果当前执行的是A协程要启动B协程就需要暂停A协程把js主线程的控制权交给B协程这样表现为A协程暂停B协程开始执行此时我们把A协程称为B协程的父协程。
分析上面的示例代码执行过程如下
js主线程执行genDemo方法生成gen协程。js主线程执行gen.next方法此时js引擎会保存当前主线程父协程调用栈信息开始执行gen协程。gen协程碰上yield关键词会保存当前gen协程的调用栈信息并将关键词后的内容返回给父协程并暂定执行gen协程恢复执行父协程即外部代码后续反复执行2和3的步骤直接主线程代码执行完。
结论
gen协程和父协程是交替执行的它们通过yield和next配合完成切换。
async/await
async
async function foo() { console.log(1); return 2
}
var p foo();
console.log(p);
// 1
// Promise { 2 }从以上代码可以得知async声明后的函数返回了一个Promise对象状态是resolved上述代码等价于
function foo() { console.log(1); return new Promise(resolve resolve(2))
}
var p foo();
console.log(p);await
async function foo() { console.log(1) let a await 100 console.log(a) console.log(2)
}
console.log(0)
foo()
console.log(3)
// 0
// 1
// 3
// 100
// 2分析执行过程
输出0主线程保存父协程调用栈信息开始执行foo协程输出1遇到await操作符await操作符干了很多事情。 let a await 100首先相当于执行了new Promise(resolve resolve(100)); 然后将主线程控制权交给父协程同时将该promise对象返回给父协程父协程调用promise对象的then方法监控promise状态的改变。输出3宏任务队列执行完成检查微任务队列执行promise对象的then方法回调并将返回值传给foo协程并执行foo协程输出100输出2完成
手动实现async、await
1. 创建启动函数**传入生成器函数**判断传入值是否生成器函数
2. 创建执行函数**接收一个参数**每次 next 后的返回值 { value , done }
- 通过判断 v.done 决定递归是否结束
- 递归执行自身并判断返回值如果是 **promise对象** 就调用 .then 等待异步执行后执行 next 并将 promise 结果传入如果是**基本类型**就直接执行 next 函数传入 value 值即可
3. **执行启动函数**传入generator.next() // promise 函数
function getData (data, time 1000) {// 返回 promise 对象if (typeof data object) {return new Promise(function (resolve, reject) {setTimeout(function () {resolve(data)}, time)})}// 返回普通类型else {return data}
}// function* async function
function* test () {let res1 yield getData(字符串); // yield awaitconsole.log(res1, res1);let res2 yield getData({ data: [1, 2, 3] });console.log(res2, res2);let res3 yield getData({ data: { a: 1 } }, 3000);console.log(res3, res3);let res4 yield getData(true);console.log(res4, res4);
}// async await 底层原理启动一个自执行的生成器函数
function start (fn) {// 1 判断是否传入生成器函数if (fn.constructor.name ! GeneratorFunction) {throw new Error(it is not a generator function.)}// 2 执行获取生成器对象let generator fn()// 3 创建一个执行函数val 执行 next 函数后的值let execute (val) {// 1 递归结束if (val.done) return;// 2 判断类型if (val.value instanceof Promise) {// 3 递归执行val.value.then(res {execute(generator.next(res))}, err {generator.throw(err)})} else {// 3 递归执行Promise.resolve(val.value).then(res {execute(generator.next(res))})}}// 4 启动执行函数execute(generator.next())
}console.log(1);
start(test)
console.log(2);