JavaScript生成器,如何理解await和yield的异步组合?
发布于 作者:苏南大叔 来源:程序如此灵动~当关键字yield
碰到关键字await
,那么function*
必然会遇到关键字async
,它们并不冲突,并且可以合理组合到一起。本文就将通过“异步函数生成器”的使用方式,做一些简要探讨。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,chrome@131.0.6778.205
。在浏览器或者纯node
环境下,都可以运行本文的“异步函数生成器”。
准备工作
主要包括两部分:express
代码,await
理论。
配套express代码
为了演示异步函数处理,这里使用express
临时搭建一个接口处理函数。代码如下:
const express = require("express");
const app = express();
var cors = require("cors");
app.use(cors());
app.all("*", (req, res) => {
let ret = {
url: req.url,
time: Date.now().toString().slice(-6),
};
res.send(JSON.stringify(ret));
});
const server = app.listen(process.env.PORT || 3222, () => {
const port = server.address().port;
console.log("http://localhost:%d", port);
});
await返回值
最典型的异步处理,就是fetch()
一个接口了。那么,对于await fetch()
来说,它的返回值,先后是promise
=>reponse
=>json string
=>json object
。似乎在以往的代码里面,都遇到过。
await
的返回值是什么类型,并不决定于await
关键字,也不决定于fetch()
函数。而是决定于fetch()
后面的.then()
和catch()
。因为这个promise()
的链式处理,返回什么样的值都是可能的。
(async () => {
let api = "http://localhost:3222/s/n";
const r1 = fetch(api);
// Promise { <pending> }
const r2 = await fetch(api);
// Response { status: 200, ... }
const r3 = await fetch(api).then((res) => res);
// Response { status: 200, ... }
const r4 = await fetch(api).then((res) => res).then((res) => res.json())
// { url: '/s/n', time: '581603' }
})();
异步函数和生成器
下面的两个代码,看起来非常类似。仅仅是关键字yield
和await
的相互替换。但是,两者的结果走向完全不同。
async function fetchData() {
const response = await fetch("http://localhost:3222/s/n");
return await response.json();
}
fetchData().then((data) => {
console.log(data); // { url: '/s/n', time: '892693' }
});
相同的效果,因为这个response = yield fetch()
的返回值导出又导入的特殊设定,导致多走很多冤枉路。
function* fetchData2() {
const response = yield fetch("http://localhost:3222/ss/nn");
yield response.json();
}
const gen = fetchData2();
const promise_1 = gen.next().value;
promise_1.then((response) => {
const promise_2 = gen.next(response).value; // 这里又传回去了
promise_2.then((data) => {
console.log(data); // { url: '/s/n', time: '892693' }
});
});
异步函数生成器【出乎意料】
本段代码就是异步函数生成器了,上面的代码的综合体。async function*
+ yield await
。所以,新的代码逻辑下,又会是什么样的逻辑走向呢?
async function* fetchData3() {
const response = yield await fetch("http://localhost:3222/ss/nn");
yield await response.json();
}
const gen = fetchData3();
const promise_1 = gen.next(); // 这里写法不同
promise_1.then((response) => {
const promise_2 = gen.next(response.value); // 这里又传回去了,注意这里写法不同
promise_2.then((data) => {
console.log(data.value); // { url: '/s/n', time: '892693' },这里写法不同
});
});
这段代码,又又又打破认知了!!!
用了很久才接受的yield
的返回值是{value:'',done:false}
这事儿,在async function*
里面,变成了要返回的是就是value
(没有外部套着的那些)。然后再.then()
一下,才会变成认知中的{value:'',done:false}
的格式。
也就是说yield
的概念再次分裂了!
没有await的异步生成器
上面代码里,如果把【await
关键字全部去掉】,保持async
字样的话,上面的代码结论依然成立。
async function* fetchData3() {
const response = yield fetch("http://localhost:3222/ss/nn");
yield response.json();
}
const gen = fetchData3();
const promise_1 = gen.next(); // 这里写法不同
promise_1.then((response) => {
const promise_2 = gen.next(response.value); // 这里又传回去了,注意这里写法不同
promise_2.then((data) => {
console.log(data.value); // { url: '/s/n', time: '892693' },这里写法不同
});
});
相关文章
- https://newsn.net/say/js-yield-await.html
- https://newsn.net/say/js-yield-star.html
- https://newsn.net/say/js-yield-2.html
- https://newsn.net/say/js-yield.html
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。