在线做的网站,网站建设公众号小程序推广开发,南宁网站建设业务员,wordpress图片插件使用教程三种语法功能放在一起#xff0c;是因为他们都有相似特点#xff1a;
维护某种状态在未来恢复状态并执行
本文重点回答以下几个问题#xff1a;
为什么 Generator 和 Async 函数的 代码执行流 都可以简化成树形结构#xff1f;async 函数为什么返回一个 promise#xf…三种语法功能放在一起是因为他们都有相似特点
维护某种状态在未来恢复状态并执行
本文重点回答以下几个问题
为什么 Generator 和 Async 函数的 代码执行流 都可以简化成树形结构async 函数为什么返回一个 promise返回了怎样一个 promiseasync 函数如何优雅的转换成 promise 函数 Generator 用法和思考
基本生成器
generator 是生成器从生成器的行为来看它就是一个迭代器。
function* foo(end) {var idx 0;while (idx end) {yield idx; // 保存当前状态并返回 当前idxidx 5;}
}const iterator foo(20);
// iterator.next().value 手动迭代
for (let val of iterator { // 输出 0 到 19console.log(val);
}对应到生成器函数中他会在 yield 的时候保存当前函数的状态。那么函数的状态保存在哪 习惯了 C 函数的我们很难想象如何将状态保存在函数中。可能协程和 setjmp/longjmp 可以辅助我们思考生成器的实现但还是不能直接对应到生成器函数的行为。比如生成器需要记录如下信息
Idx 的大小 end 大小pc 指针在 第 5 行
想在 c 语言中保存上述信息是不容易的。是因为函数在 js 是第一类值上述的信息便可以保存在函数值本身内。对应quickjs 相当于将 pc 指针 和 参数 信息local_buf保存在对应的函数对象 (实际上保存在 StackFrame 中) 内而 cur_ref 信息 quickjs 本身就已经保存了。而 c/c 语言的函数没有类似功能。
嵌套多层迭代器
树形生成器结构。讲 yield 这种语法是因为它跟 async 的执行流非常像但会可以看到使用树形生成器生成 0 ~ 20 的值
function* inner(index) {var i 0;while (i 5) {yield index i;i;}
}// 错误的生成器用法但是启发我们思考这样的用法是不是很像 await?
// function* foo(index) {
// while (index 20) {
// yield inner(index);
// index 5;
// }
// }// 正确版本
function* foo1(index) {while (index 20) {var it inner(index);for (let val of it) {yield val;}index 5;}
}// 语法糖版本
function* foo2(index) {while (index 20) {yield *inner(index);index 5;}
}const iterator foo1(0);for (let val of iterator) {console.log(val);
}async 执行流的思考 Async 的代码执行流程是下面这棵树的中序遍历 Async 函数的代码执行流程如下 先执行绿色部分代码直到最底层的 promise由于promise 测试未决定(pending 状态)整个函数暂停退出。promise resolve或reject 后恢复中序遍历执行淡蓝色部分代码直到下一个 promise。这里相当于执行了 promise 的 then 回调。 Plus. 这里仍然有一次 暂停执行。因为 新的 promise 是 pending 状态。 新的 promise resolve或reject 后继续恢复执行 。。。。Async 函数的结尾的 return 道理上相当于一个 then 回调 Async 函数的代码执行流程非常像 树形 generator 都说 async 函数返回一个 promise它返回的 promise 到底是什么 Async 函数框架
async function asyncfunc() {code1;var a1 await asyncfunc1(); // 这里是一个 async 函数code2;var a2 await promise1; // 这里是一个 真正的 Promisecode3;var a3 await asyncfunc2(); // 这里是一个 async 函数codeR;return x;
}asyncfunc();可以尝试使用如下代码单步调试来验证
async function wrapFetch(url) {console.log(wrapFetch code1);const response await fetch(url);console.log(wrapFetch code2);return response;
}// 异步函数示例
async function fetchAsyncData() {console.log(fetchAsyncData code1);const response await wrapFetch(https://qqlykm.cn/api/weather/get);console.log(fetchAsyncData code2 ok?, response.ok);const data await response.json();console.log(data);
}// 调用异步函数
console.log(before async);
fetchAsyncData();
console.log(after async);问题能把 async 函数串行化么答案是不能。只要使用了 promise (叶子节点是真正的 promise)代码的执行就要遵循 promise 的执行规则而 promise 本身就是异步的因此无法串行化。
一点点 Promise 的思考
想要理解如何将 async 函数返回的到底是什么 promise以及如何将 async 函数翻译成一个 promise 的形式需要深入理解 then 函数。
Then 函数
Then 函数返回一个 promise称其为 p。Then 注册的回调函数中也会返回一个值。那么 返回 一个值 和 返回一个 promise 有什么不同如果回调函数返回了 promise那么这个promise 和 then 返回的 promise p 是 什么关系官方文档链式调用。 结论他俩在行为上是 同一个 promise知道这一点就可以轻松的把一个 async 函数改写成 promise 的形式了。
const myPromise new Promise((resolve, reject) {// 进行异步操作const randomNumber Math.random();// 如果操作成功调用resolve并传递结果resolve(randomNumber);
});// 使用Promise对象
myPromise.then(result {// 操作成功时的处理逻辑console.log(操作成功结果为 result);**return 1; ****return new Promise((rs, rj) rs(2));**}).then( val {console.log(val);})将 async 改写成 promise
如何改写下面用一个示例来展示 注这里并没有关注异常执行流而是只关注异步执行流。异常执行流要想完全转换需要在promise里注册错误回调并且 async 和 promise 都要捕获异常 // async 写法async function asyncfunc() {code1;var a1 await asyncfunc1(); // 这里是一个 async 函数code2;var a2 await promise1; // 这里是一个 真正的 Promisecode3;var a3 await asyncfunc2(); // 这里是一个 async 函数codeR;return x;
}asyncfunc();// 等价的promise 写法function func() {return new Promise((resolve, reject) {code1;func1().then( (val) resolve(val) );}).then((a1) {code2;return promise1;}).then((a2) {code3;// 返回一个Promisereturn func2(); }).then((a3) {codeR;return x;});
}
func();结论async 语法糖有什么好处呢
代码写起来更简洁、优雅意味着 减少出错率词法作用域更广。写 code2 可以用 code1 部分的变量写 promise 的时候就没办法了。
可验证代码
异步调用一个 网络 api 接口
async 版本
async function wrapFetch(url) {console.log(wrapFetch code1);const response await fetch(url);console.log(wrapFetch code2);return response;
}// 异步函数示例
async function fetchAsyncData() {console.log(fetchAsyncData code1);const response await wrapFetch(https://qqlykm.cn/api/weather/get);console.log(fetchAsyncData code2 ok?, response.ok);const data await response.json();console.log(data);
}// 调用异步函数
console.log(before async);
fetchAsyncData();
console.log(after async);等价 Promise 版本
function wrapFetch(url) {return new Promise( function (resolve, reject) {console.log(wrapFetch code1);fetch(url).then( (response) {resolve(response);console.log(wrapFetch code2);})});
}function fetchAsyncData() {return new Promise(function (resolve, reject) {console.log(fetchAsyncData code1);wrapFetch(https://qqlykm.cn/api/weather/get).then( val resolve(val) )}).then( (response) {console.log(fetchAsyncData code2 ok?, response.ok);return response.json()}).then((data) {console.log(data);});
}// 调用异步函数
console.log(before async);
fetchAsyncData();
console.log(after async);