传统 Ajax 已死,Fetch 永生

最近把 生意参谋 全部请求由 jQuery 的 $.ajax 迁移到 Fetch,上线2个月以来运行非常稳定。结果证明,对于 IE8+ 以上浏览器,在生产环境使用 Fetch 是可行的。

原谅我做一次标题党,Ajax 不会死,传统 Ajax 指的是 XMLHttpRequest(XHR), 未来 现在已被 Fetch 替代。

由于 Fetch API 是基于 Promise 设计,有必要先学习一下 Promise,推荐阅读 MDN Promise 教程。旧浏览器不支持 Promise,需要使用 polyfill es6-promise 。

本文不是 Fetch API 科普贴,其实是讲异步处理和 Promise 的。Fetch API 很简单,看文档很快就学会了。推荐 MDN Fetch 教程 和 万能的WHATWG Fetch 规范

Why Fetch

XMLHttpRequest 是一个设计粗糙的 API,不符合关注分离(Separation of Concerns)的原则,配置和调用方式非常混乱,而且基于事件的异步模型写起来也没有现代的 Promise,generator/yield,async/await 友好。

Fetch 的出现就是为了解决 XHR 的问题,拿例子说明:

使用 XHR 发送一个 json 请求一般是这样:

var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'json';

xhr.onload = function() {
  console.log(xhr.response);
};

xhr.onerror = function() {
  console.log("Oops, error");
};

xhr.send();

使用 Fetch 后,顿时看起来好一点

fetch(url).then(function(response) {
  return response.json();
}).then(function(data) {
  console.log(data);
}).catch(function(e) {
  console.log("Oops, error");
});

使用 ES6 的 箭头函数 后:

fetch(url).then(response => response.json())
  .then(data => console.log(data))
  .catch(e => console.log("Oops, error", e))

现在看起来好很多了,但这种 Promise 的写法还是有 Callback 的影子,而且 promise 使用 catch 方法来进行错误处理的方式有点奇怪。不用急,下面使用 async/await 来做最终优化:

注:async/await 是非常新的 API,属于 ES7,目前尚在 Stage 1(提议) 阶段,这是它的完整规范。使用Babel 开启 runtime 模式后可以把 async/await 无痛编译成 ES5 代码。也可以直接使用 regenerator 来编译到 ES5。

try {
  let response = await fetch(url);
  let data = response.json();
  console.log(data);
} catch(e) {
  console.log("Oops, error", e);
}
// 注:这段代码如果想运行,外面需要包一个 async function

duang~~ 的一声,使用 await 后, 写异步代码就像写同步代码一样爽 。await 后面可以跟 Promise 对象,表示等待 Promise resolve() 才会继续向下执行,如果 Promise 被 reject() 或抛出异常则会被外面的 try...catch 捕获。

Promise,generator/yield,await/async 都是现在和未来 JS 解决异步的标准做法,可以完美搭配使用。这也是使用标准 Promise 一大好处。最近也把项目中使用第三方 Promise 库的代码全部转成标准 Promise,为以后全面使用 async/await 做准备。

另外,Fetch 也很适合做现在流行的同构应用,有人基于 Fetch 的语法,在 Node 端基于 http 库实现了 node-fetch,又有人封装了用于同构应用的 isomorphic-fetch

注:同构(isomorphic/universal)就是使 前后端运行同一套代码 的意思,后端一般是指 NodeJS 环境。

总结一下,Fetch 优点主要有:

  1. 语法简洁,更加语义化
  2. 基于标准 Promise 实现,支持 async/await
  3. 同构方便,使用 isomorphic-fetch

Fetch 启用方法

下面是重点↓↓↓

先看一下 Fetch 原生支持率:

原生支持率并不高,幸运的是,引入下面这些 polyfill 后可以完美支持 IE8+ :

  1. 由于 IE8 是 ES3,需要引入 ES5 的 polyfill: es5-shim, es5-sham
  2. 引入 Promise 的 polyfill: es6-promise
  3. 引入 fetch 探测库:fetch-detector
  4. 引入 fetch 的 polyfill: fetch-ie8
  5. 可选:如果你还使用了 jsonp,引入 fetch-jsonp
  6. 可选:开启 Babel 的 runtime 模式,现在就使用 async/await

Fetch polyfill 的基本原理是探测是否存在 window.fetch 方法,如果没有则用 XHR 实现。这也是 github/fetch 的做法,但是有些浏览器(Chrome 45)原生支持 Fetch,但响应中有中文时会乱码,老外又不太关心这种问题,所以我自己才封装了 fetch-detector 和 fetch-ie8 只在浏览器稳定支持 Fetch 情况下才使用原生 Fetch。这些库现在 每天有几千万个请求都在使用,绝对靠谱 !

终于,引用了这一堆 polyfill 后,可以愉快地使用 Fetch 了。但要小心,下面有坑:

Fetch 常见坑

  • Fetch 请求默认是不带 cookie 的,需要设置 fetch(url, {credentials: 'include'})
  • 服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。

竟然没有提到 IE,这实在太不科学了,现在来详细说下 IE

IE 使用策略

所有版本的 IE 均不支持原生 Fetch,fetch-ie8 会自动使用 XHR 做 polyfill。但在跨域时有个问题需要处理。

IE8, 9 的 XHR 不支持 CORS 跨域,虽然提供 XDomainRequest,但这个东西就是玩具,不支持传 Cookie!如果接口需要权限验证,还是乖乖地使用 jsonp 吧,推荐使用 fetch-jsonp。如果有问题直接提 issue,我会第一时间解决。

Fetch 和标准 Promise 的不足

由于 Fetch 是典型的异步场景,所以大部分遇到的问题不是 Fetch 的,其实是 Promise 的。ES6 的 Promise 是基于Promises/A+ 标准,为了保持 简单简洁 ,只提供极简的几个 API。如果你用过一些牛 X 的异步库,如 jQuery(不要笑) 、Q.js 或者 RSVP.js,可能会感觉 Promise 功能太少了。

没有 Deferred

Deferred 可以在创建 Promise 时可以减少一层嵌套,还有就是跨方法使用时很方便。
ECMAScript 11 年就有过 Deferred 提案,但后来没被接受。其实用 Promise 不到十行代码就能实现 Deferred:es6-deferred。现在有了 async/await,generator/yield 后,deferred 就没有使用价值了。

没有获取状态方法:isRejected,isResolved

标准 Promise 没有提供获取当前状态 rejected 或者 resolved 的方法。只允许外部传入成功或失败后的回调。我认为这其实是优点,这是一种声明式的接口,更简单。

缺少其它一些方法:always,progress,finally

always 可以通过在 then 和 catch 里重复调用方法实现。finally 也类似。progress 这种进度通知的功能还没有用过,暂不知道如何替代。

不能中断,没有 abort、terminate、onTimeout 或 cancel 方法

Fetch 和 Promise 一样,一旦发起,不能中断,也不会超时,只能等待被 resolve 或 reject。幸运的是,whatwg 目前正在尝试解决这个问题 https://github.com/whatwg/fetch/issues/27

最后

Fetch 替换 XHR 只是时间问题,现在很多新的库都默认使用了 Fetch。

最后再做一个大胆预测:由于 async/await 这类新异步语法的出现,第三方的 Promise 类库会逐渐被标准 Promise 替代,使用 polyfill 是现在比较明智的做法。

此文有整理,原发于我的博客 https://github.com/camsong/blog/issues/2

时间: 2024-10-30 23:18:39

传统 Ajax 已死,Fetch 永生的相关文章

李善友:传统营销已死粉丝的钱比用户的钱好赚

粉丝的钱比用户的钱好赚. 全世界所有的手机厂商只有苹果和三星是赚钱的,其中苹果就占到全球利润的73%.所以按理讲,手机并不是一个好生意.但是今年,有人出2亿多美金,换取小米5%的股权,估值达40亿美金.小米居然成了全世界第3个赚钱的手机公司.普遍分析,小米的成功模式主要有3条:第一,零费用的营销成本:第二,零费用的渠道成本:第三,零库存的预购模式.今天我重点分析一下第一条. 我之前在搜狐工作的时候,包括自己做酷6时,手机厂商一直是我最大的客户.一般来说,他们每年的广告费用都在5亿元到10亿元,比

李善友:传统营销已死 粉丝的钱比用户的钱好赚

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 粉丝的钱比用户的钱好赚. 全世界所有的手机厂商只有苹果和三星是赚钱的,其中苹果就占到全球利润的73%.所以按理讲,手机并不是一个好生意.但是今年,有人出2亿多美金,换取小米5%的股权,估值达40亿美金.小米居然成了全世界第3个赚钱的手机公司.普遍分析,小米的成功模式主要有3条:第一,零费用的营销成本;第二,零费用的渠道成本;第三,零库存的预购

李善友:传统营销已死

<哈佛商业评论>曾经写了一篇文章,"传统营销已死":包括广告宣传.公共关系.品牌管理以及企业传媒在内的传统营销手段都已经失效.很多还在这一行的人们似乎还没有意识到,他们所在的部门或者组织已经只剩下躯壳了.而建立于同伴影响力和社区导向的新型营销手段已经登上舞台,通过真正的顾客关系,它将为企业创造持续的增长.很显然,小米手机提供了一个很好的思路.粉丝的钱比用户的钱好赚全世界所有的手机厂商只有苹果和三星是赚钱的,其中苹果就占到全球利润的73%.所以按理讲,手机并不是一个好生意.但

年终盘点:解读2016之容器篇——“已死”和“永生”

也说不上什么时候起,"XXX Is Dead. Long Live XXX"的句式突然成为了技术会议上演讲题目的一个标准套路.然而不管已经被引用的多么烂俗,用这套悖论来总结2016年容器技术圈子发生的凡事种种,却实在有种说不出来的恰到好处. 无需多言,稍微回顾一下2016年容器技术圈子的时间线,我们很容易就能回想起容器技术如何在这一年迅速登上云计算舞台的中心.这股热潮,从年初Docker公司闪电收购Unikernel Systems提前扼杀各种"被颠覆"的苗头,蔓延

《连线》杂志:网站已死互联网永生

网站在互联网领域的比重正在下降 导语:<连线>杂志网站近日发表文章,对网站在整个互联网领域中衰落的原因进行了分析. 以下是文章全文: 从诞生到现在,网站已经走过了20个年头.相比当年的流行,如今它已经开始衰落,逐渐让位于更简单且时髦的智能应用.这些应用更关注的不是搜索效果,而是信息获取.克莱斯·安德森(Chris Anderson)向我们解释了这些新应用所反映的资本聚焦点的变化.而米歇尔·沃夫(Michael Wolff)则向我们解释了新一代媒体大亨们为什么会放弃网站转而寻找更有前景(其实就是

《连线》杂志:Web已死 Internet永生(全文),互联网营销

网站在互联网领域的比重正在下降 导语:<连线>杂志网站近日发表文章,对Web在整个互联网领域中衰落的原因进行了分析. 以下是文章全文: 从诞生到现在,Web已经走过了20个年头.相比当年的流行,如今它已经开始衰落,逐渐让位于更简单且时髦的智能应用.这些应用更关注的不是搜索效果,而是信息获取.克莱斯·安德森(Chris Anderson)向我们解释了这些新应用所反映的资本聚焦点的变化.而米歇尔·沃夫(Michael Wolff)则向我们解释了新一代媒体大亨们为什么会放弃Web转而寻找更有前景(其

传统营销已死取悦“粉丝”当道

对于一个"80后"而言,如果想留住你童年的记忆--肯德基吮指原味鸡,那你就要参加"谁能代表肯德基 由你来投票"的炸鸡PK活动;而对于一个"90后"而言,如果要想留住你现在的最爱--黄金脆皮鸡,也要通过投票的方式实现.将一个产品的去留完全交给消费者去决定,这在一个传统餐饮品牌的营销历史上是很少的,而肯德基的营销创新也算是融入了当下最热门的互联网思维--让粉丝参与决定产品的走向.提到当下最热门的互联网思维,人们几乎都可以联想到那些热门的名字:马佳佳.

写在GoogleI/O前:手环已死,可穿戴永生

我拥有的第一款可穿戴设备是Nike+ Sport Watch,其已被我送人并且吃灰一年多.第二款可穿戴设备是Fitbit Flex,在努力带满一个月之后它躺进了抽屉.我还试戴了Google Glass.Jawbone.Shine.inWatch.hiWatch等市面上流行的可穿戴设备,坦率地讲没有一款可穿戴设备真正打动我,让我愿意为之买单,哪怕是一张电影票的价钱. 手环:去解决并不存在的问题 市面上任何一款手环,都无法说服我为之买单或者说持续使用它们. 相比普通的智能健康手环,Fitbit 做工

软件已死,数据永生!

近二个多月来,在几个会议上听到王总在谈"软件已死,数据永生",在YOP的会议上,王总谈到他对未来信息化趋势的思考: 1.云计算,云是后台,是基础设施,是计算架构 云计算可降低IT运营成本2. 终端是移动终端,PC将会是第二位的3.以数据为中心 软件已死.数据永生4. 大数据http://www.aliyun.com/zixun/aggregation/20795.html">处理技术的应用5.社区.工作圈.微信的应用6.前台应用的碎片化我们就是软件行业,能谈"