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

本文说的这个defer()很有意思,它并非nodejs原生的,它来自于ReactRouter,并且将在下一个ReactRouter@v7里面被废除。目前的ReactRouter@v6版本里面,它还是能够使用的。它惊艳到苏南大叔的地方在于:它打破了async+await的固定组合,提供了一个新的通过promise获取数据的可能性。

苏南大叔:React路由,数据获取相关函数defer(),await之外另一选择 - react-defer
React路由,数据获取相关函数defer(),await之外另一选择(图4-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1。本文的defer是个包装函数,并非原生自带,来自于ReactRouter,并且即将被ReactRouter@v7废弃。

哪个defer?

以前苏南大叔写过一个script标签的defer属性。本文的defer()和这个defer属性是没有半毛钱关系的。纯属巧合。前文链接:

本文的refer并不是nodejs原生自带,而是由reactrouter提供的导出函数,并且还不是更加常见的react hook。并且,极有可能能够脱离react路由独立使用。这,就非常非常的不react了。

对于同一个耗时的Promise请求,本文就存在着两种不同的写法了。分别是awaitdefer。对于react程序来说,await是串行,阻碍渲染。defer是并行,并不阻碍页面渲染。

基础耗时请求

const getData = () => {
  return new Promise((r) => {
    setTimeout(() => {
      r({ name: "苏南大叔" });
    }, 3000);
  });
};

经常使用setTimeout()来模拟远程接口返回,实际的应用中,确是经常使用axios来做这个请求的。参考文章:

const getData = () => {
  return new Promise((r) => {
    const axios = require('axios');
      axios.get("http://127.0.0.1:3222/hello").then(res => {
        r(res.data);
      })
      .catch(err => {
          // reject();
      });
  });
};

写法一,async + await

对于promise来说,一直无法脱离asyncawait的影子。有的时候,会为了一些写法,硬生生的在函数定义前面加上个async字样,很令人无语。

当然,本文中的await就是原生的await,并不是react router里面的<Await>

参考代码:

const r1 = getData();
r1.then((a) => {
  console.log(a, "then");
});

const r2 = await getData();  // 有条件执行
console.log(r2, "await");

(async () => {
  const r3 = await getData();
  console.log(r3, "async + await");
})();

苏南大叔:React路由,数据获取相关函数defer(),await之外另一选择 - async+await测试
React路由,数据获取相关函数defer(),await之外另一选择(图4-2)

写法二,本文主角defer

参考测试代码:

import { defer } from "react-router-dom";
const ppp = getData();
const rrr = defer({ ppp });

这里的ppp变量是个promise,而rrr是个自定义的DeferredData类型。

单独使用defer的时候,肯定是可以独立运行的,并不需要任何react router的定义。由于没有相关文档,最好的解析返回值数据的方法,目前并不知晓。但是,可以在适当的时候(比如:promise成功后),通过下面的方式获得数据。

rrr.unwrappedData.ppp

苏南大叔:React路由,数据获取相关函数defer(),await之外另一选择 - defer结果,时间的掌控很重要
React路由,数据获取相关函数defer(),await之外另一选择(图4-3)

这个地方,测试结果和时间的掌控关系密切。在promise结果返回之前,console.log里面输出的DeferredData对象的.unwrappedData属性,点开是个错误信息提示。而promise结果返回之后,点开的话,是个正常显示的数据。难道这个.unwrappedData属性,是个未决的属性?

苏南大叔:React路由,数据获取相关函数defer(),await之外另一选择 - deferered-data
React路由,数据获取相关函数defer(),await之外另一选择(图4-4)

当然,react router里面,并不是通过上述方法,获得返回值的。具体的获得方式,待后续文章讨论。

可能遇到的问题

测试过程,也是较多波折的。出于前后文章延续测试的目的,本文的代码,是完全替换了cra模版的src/index.js文件。

普通的await版本测试,因为代码里面有直接写的await(不带async)。直接放在index.js里面,npm start的话,会得到错误提示:

Module parse failed: Top-level-await is only supported in EcmaScript Modules

那么node index.js的话,会得到提示:

SyntaxError: await is only valid in async functions and the top level bodies of modules

那么,解决方案有两个。

  • 一个是联合后续的defer测试,在顶部添加import字样。那么,就可以直接npm start看结果了。【纯属歪打正着】
  • 或者,修改index.js文件名为index.mjs。然后node index.mjs,就可以单独测试async+await的结果了。

结语

这个defer()的写法,打破了async+await的万年垄断。苏南大叔翻了翻代码,好像实现上有个.subscribe()方法。使用这个订阅方法的各种环境中,都是有一种非常轻松的氛围的。比如socket或者redis

更多react的经验文章,请参考苏南大叔的博客:

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

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

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

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