标签 fetch 下的文章

本文记录了从jQurey转到原生JavaScript开发的相关处理。

一 历史

二十一世纪初,IE 6还在统治浏览器的时代,出现了一批JavaScript框架。除了提高前端开发效率,还屏蔽了各个浏览器的JavaScript接口差异。那时有3个产品印象比较深刻:

  1. prototype,http://prototypejs.org/
    其特点是在原生JavaScript基础上做扩展,定义通用的方法或接口,屏蔽各个浏览器的差异。很轻量,个人比较喜欢。
  2. Ext JS,https://www.sencha.com/products/extjs/
    数据与界面分离,提供丰富的UI组建,便于页面开发。当时浏览器JavaScript性能不高,用起来不够流畅,不适合简单排版布局的页面。但是对于开发一些管理系统,确实很方便。
  3. jQuery,https://jquery.com/
    最大特别是查找HTML元素很方便(前提是熟悉其搜索语法),有点函数式编程的味道。在那个需要手工修改HTML界面的年代,确实很方便。

二 当前

看看当前的浏览器,已经是Webkit内核的天下,加上IE已亡,ECMAScript 6普及……各个浏览器的JavaScript兼容性大大提高。所以,我们可以直接采用浏览器原生JavaScript,替代jQuery这类用于遍历或搜索DOM的框架。当然,复杂的界面,主要是响应式前端框架(AngularJS、React、VUE)的世界。

三 实现方法

主要参考这个文章,从jQuery转到原生JavaScript。

另外,对于页面上的异步请求(ajax),该文章没有提出timeout的处理。以下整理一个示例:

// 请求错误的类,用于传递错误信息
let RespError = class {
  constructor(code, msg, respJson) {
    this.code = code;
    this.msg = msg;
    this.respJson = respJson;
  }
};

// POST提交Json数据。调用ajaxJson方法前加上async就是同步调用,直接调用就是异步调用
// 默认超时10秒
let ajaxJson = async (url, formParam={}, onSuccess=(respJson)=>{}, 
    onFailed=(respError)=>{}, timeoutSec=10) => {
  let controller = new AbortController();
  let timeoutId = setTimeout(() => {
    // 超时后停止请求
    controller.abort();
    // 抛出超时的错误
    onFailed(new RespError(-1, 'TIMEOUT', null));
  }, timeoutSec * 1000);
  try {
    // 发起请求
    let response = await fetch(url, {
        signal: controller.signal, // 用于接收中断请求信号
        method: 'POST',
        cache: 'no-cache',
        headers: {
          // 声明请求的参数是JSON
          'Content-Type': 'application/json; charset=UTF-8'
        },
        body: JSON.stringify(formParam)
    });
    // 注意,响应的数据只能获取一次,包括response.json()和response.text()
    let respJson = await response.json();
    if(!response.ok) {
      // 请求失败,抛出自定义的错误对象
      throw new RespError(response.status, response.statusText, respJson);
    }
    onSuccess(respJson);
  } catch(err) {
    onFailed(err instanceof RespError ? err : new RespError(-1, err.message, null));
  } finally {
    // 请求结束,停止执行定时函数。避免相应成功后,抛出超时的错误。
    clearTimeout(timeoutId);
  }
};

关于Fetch的使用,参考:

  1. Fetch API 教程
    https://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html
  2. mdn web docs - 使用 Fetch
    https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

四 后记

推荐搭配 petite-vue ,实现数据与页面元素的绑定。

这星期做了个报表,统计一堆关键词在Solr的搜索结果数量。一开始是计划写Java代码去访问Solr,并获取各个关键词的查询结果数量。后来为了减轻服务器压力,把数据下载到本地并重建了Solr索引。那为什么不用简单快速的JavaScript?

JavaScript的数据请求,可用原生的XMLHttpRequest,jQuery的$.ajax,或者fetch。记得N年前看过吹嘘fetch的文章,于是就选了fetch玩玩。该文章如下:
传统 Ajax 已死,Fetch 永生
https://github.com/camsong/blog/issues/2

说说感受吧:

1)如果需要“同步”请求,需要配合asyncawait使用,里面还要用到function。一下子不适应,$.ajax只需设置async参数。

2)不支持跨域。尝试按教程去设置fetch请求的Header,仍是不行。简单来说,需要服务端设置可跨域相关。那就简单点,把包含代码的HTML文件丢到Solr的本地站点,然后Chrome访问。

3)Promise语法很新鲜。当然,写得不好,也可以很糟糕。

4)关于错误处理,就不写了,本地请求一般不会出错。

总的来说,没想象中那么牛X,也没那么爽。如果面对一般情况,不想写复杂的XMLHttpRequest,也不想引用庞大的jQuery,不用兼容老版浏览器,fetch是个好家伙。例如这个文章提到:
fetch 没有你想象的那么美
http://undefinedblog.com/window-fetch-is-not-as-good-as-you-imagined/

还有Mozilla的参考教程,说得比较详细:
使用 Fetch - Web API 接口参考 | MDN
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch