AJAX半遮半掩的底层API是饱受诟病的一件事情. XMLHttpRequest 并不是专为Ajax而设计的. 虽然各种框架对 XHR 的封装已经足够好用, 但我们可以做得更好。更好用的API是 fetch 。下面简单介绍 window.fetch 方法, 在最新版的 Firefox 和 Chrome 中已经提供支持。
XMLHttpRequest
在我看来 XHR 有点复杂, 我不想解释为什么“XML”是大写,而“Http”是“dej式”写法。使用XHR的方式大致如下:
// 获取 XHR 非常混乱!if window.XMLHttpRequest) { // Mozilla, Safari, … request = new XMLHttpRequest);} else if window.ActiveXObject) { // IE try { request = new ActiveXObject’Msxml2.XMLHTTP’); } catch e) { try { request = new ActiveXObject’Microsoft.XMLHTTP’); } catch e) {} }}// 打开连接, 发送数据.request.open’GET’, ‘https://davidwalsh.name/ajax-endpoint’, true);request.sendnull);
我们可以看出, XHR 其实是很杂乱的; 当然, 通过 JavaScript 框架可以很方便地使用XHR。
fetch 的基本使用
fetch 是全局量 window 的一个方法, 第一个参数是URL:
// url 必须), options 可选)fetch’/some/url’, { method: ‘get’}).thenfunctionresponse) {}).catchfunctionerr) { // 出错了;等价于 then 的第二个参数,但这样更好用更直观 :});
和 Battery API 类似, fetch API 也使用了 JavaScript Promises 来处理结果/回调:
// 对响应的简单处理fetch’/some/url’).thenfunctionresponse) {}).catchfunctionerr) { // 出错了;等价于 then 的第二个参数,但这样更直观 :});// 链式处理,将异步变为类似单线程的写法: 高级用法.fetch’/some/url’).thenfunctionresponse) { return //… 执行成功, 第1步…}).thenfunctionreturnedValue) { // … 执行成功, 第2步…}).catchfunctionerr) { // 中途任何地方出错…在此处理 : });
如果你还不习惯 then 方式的写法,那最好学习一下,因为很快就会全面流行。
请求头Request Headers)
自定义请求头信息极大地增强了请求的灵活性。我们可以通过 new Headers) 来创建请求头:
// 创建一个空的 Headers 对象,注意是Headers,不是Headervar headers = new Headers);// 添加append)请求头信息headers.append’Content-Type’, ‘text/plain’);headers.append’X-My-Custom-Header’, ‘CustomValue’);// 判断has), 获取get), 以及修改set)请求头的值headers.has’Content-Type’); // trueheaders.get’Content-Type’); // “text/plain”headers.set’Content-Type’, ‘application/json’);// 删除某条请求头信息a header)headers.delete’X-My-Custom-Header’);// 创建对象时设置初始化信息var headers = new Headers{ ‘Content-Type’: ‘text/plain’, ‘X-My-Custom-Header’: ‘CustomValue’});
可以使用的方法包括: append, has, get, set, 以及 delete 。需要创建一个 Request 对象来包装请求头:
var request = new Request’/some-url’, { headers: new Headers{ ‘Content-Type’: ‘text/plain’ })});fetchrequest).thenfunction) { /* handle response */ });
下面介绍 Response 和Request 的使用方法!
Request 简介
Request 对象表示一次 fetch 调用的请求信息。传入 Request 参数来调用 fetch, 可以执行很多自定义请求的高级用法:
method – 支持 GET, POST, PUT, DELETE, HEADurl – 请求的 URLheaders – 对应的 Headers 对象referrer – 请求的 referrer 信息mode – 可以设置 cors, no-cors, same-origincredentials – 设置 cookies 是否随请求一起发送。可以设置: omit, same-originredirect – follow, error, manualintegrity – subresource 完整性值integrity value)cache – 设置 cache 模式 default, reload, no-cache)
Request 的示例如下:
var request = new Request’/users.json’, { method: ‘POST’, mode: ‘cors’, redirect: ‘follow’, headers: new Headers{ ‘Content-Type’: ‘text/plain’ })});// 使用!fetchrequest).thenfunction) { /* handle response */ });
只有第一个参数 URL 是必需的。在 Request 对象创建完成之后, 所有的属性都变为只读属性. 请注意, Request 有一个很重要的 clone 方法, 特别是在 Service Worker API 中使用时 —— 一个 Request 就代表一串流stream), 如果想要传递给另一个 fetch 方法,则需要进行克隆。
fetch 的方法签名signature,可理解为配置参数), 和 Request 很像, 示例如下:
fetch’/users.json’, { method: ‘POST’, mode: ‘cors’, redirect: ‘follow’, headers: new Headers{ ‘Content-Type’: ‘text/plain’ })}).thenfunction) { /* handle response */ });
因为 Request 和 fetch 的签名一致, 所以在 Service Workers 中, 你可能会更喜欢使用 Request 对象。关于 ServiceWorker 的相关博客请等待后续更新!
Response 简介
Response 代表响应, fetch 的 then 方法接收一个 Response 实例, 当然你也可以手动创建 Response 对象 —— 比如在 service workers 中可能会用到. Response 可以配置的参数包括:
type – 类型,支持: basic, corsurluseFinalURL – Boolean 值, 代表 url 是否是最终 URLstatus – 状态码 例如: 200, 404, 等等)ok – Boolean值,代表成功响应status 值在 200-299 之间)statusText – 状态值例如: OK)headers – 与响应相关联的 Headers 对象.
// 在 service worker 测试中手动创建 response// new ResponseBODY, OPTIONS)var response = new Response’…..’, { ok: false, status: 404, url: ‘/’});// fetch 的 `then` 会传入一个 Response 对象fetch’/’) .thenfunctionresponseObj) { console.log’status: ‘, responseObj.status); });
Response 提供的方法如下:
clone) – 创建一个新的 Response 克隆对象.error) – 返回一个新的,与网络错误相关的 Response 对象.redirect) – 重定向,使用新的 URL 创建新的 response 对象..arrayBuffer) – Returns a promise that resolves with an ArrayBuffer.blob) – 返回一个 promise, resolves 是一个 Blob.formData) – 返回一个 promise, resolves 是一个 FormData 对象.json) – 返回一个 promise, resolves 是一个 JSON 对象.text) – 返回一个 promise, resolves 是一个 USVString text). 处理 JSON响应
假设需要请求 JSON —— 回调结果对象 response 中有一个json)方法,用来将原始数据转换成 JavaScript 对象:
fetch’https://davidwalsh.name/demo/arsenal.json’).thenfunctionresponse) { // 转换为 JSON return response.json);}).thenfunctionj) { // 现在, `j` 是一个 JavaScript object console.logj); });
当然这很简单 , 只是封装了 JSON.parsejsonString) 而已, 但 json 方法还是很方便的。
处理基本的Text / HTML响应
JSON 并不总是理想的请求/响应数据格式, 那么我们看看如何处理 HTML或文本结果:
fetch’/next/page’) .thenfunctionresponse) { return response.text); }).thenfunctiontext) { // <!DOCTYPE …. console.logtext); });
如上面的代码所示, 可以在 Promise 链式的 then 方法中, 先返回 text) 结果 ,再获取 text 。
处理Blob结果
如果你想通过 fetch 加载图像或者其他二进制数据, 则会略有不同:
fetch’flowers.jpg’) .thenfunctionresponse) { return response.blob); }) .thenfunctionimageBlob) { document.querySelector’img’).src = URL.createObjectURLimageBlob); });
响应 Body mixin 的 blob) 方法处理响应流Response stream), 并且将其读完。
提交表单数据Posting Form Data)
另一种常用的 AJAX 调用是提交表单数据 —— 示例代码如下:
fetch’/submit’, { method: ‘post’, body: new FormDatadocument.getElementById’comment-form’))});
提交 JSON 的示例如下:
fetch’/submit-json’, { method: ‘post’, body: JSON.stringify{ email: document.getElementById’email’).value answer: document.getElementById’answer’).value })});
非常非常简单, 妈妈再也不用担心我的Ajax!
未完的故事Unwritten Story)
fetch 是个很实用的API , 当前还不允许取消请求, 这使得很多程序员暂时不会考虑它。
新的 fetch API 比起 XHR 更简单也更智能。毕竟,它就是专为AJAX而设计的, 具有后发优势. 而我已经迫不及待地使用了, 即使现在兼容性还不是那么好!
本文简单介绍了 fetch 。更多信息请访问 Fetch简介。如果你要使用 fetch, 也想寻找 polyfill兼容代码), 请点击: GitHub上的fetch实现 https://github.com/github/fetch。
翻译人员: 铁锚 http://blog.csdn.net/renfufei
翻译时间: 2016年5月22日
原文时间: 2016年4月15日
原文链接: https://davidwalsh.name/fetch