我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

当关键字yield碰到关键字await,那么function*必然会遇到关键字async,它们并不冲突,并且可以合理组合到一起。本文就将通过“异步函数生成器”的使用方式,做一些简要探讨。

苏南大叔:JavaScript生成器,如何理解await和yield的异步组合? - 异步生成器
JavaScript生成器,如何理解await和yield的异步组合?(图2-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0chrome@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' }
})();

异步函数和生成器

下面的两个代码,看起来非常类似。仅仅是关键字yieldawait的相互替换。但是,两者的结果走向完全不同。

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的概念再次分裂了!

苏南大叔:JavaScript生成器,如何理解await和yield的异步组合? - 代码分解
JavaScript生成器,如何理解await和yield的异步组合?(图2-2)

没有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' },这里写法不同
  });
});

相关文章

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js