fetch 是什么
XMLHttpRequest
的最新替代技术
fetch优点
- 接口更简单、简洁,更加语义化
- 基于promise,更加好的流程化控制,可以不断then把参数传递,外加 async/await,异步变同步的代码书写风格
- 利于同构,isomorphic-fetch 是对 whatwg-fetch和node-fetch的一种封装,你一份代码就可以在两种环境下跑起来了
- 新的web api很多内置支持fetch,比如 service worker
fetch 缺点
- 兼容性
- 不支持progress事件(可以借助
response.body.
getRender
方法来实现) - 默认不带cookie
- 某些错误的http状态下如400、500等不会reject,相反它会被resolve
- 不支持timeout处理
- 不支持jsonp,当然可以引入 fetch-jsonp 来支持
这些缺点,后面的参考里面有各种解决方案
fetch兼容性(2017-08-08):
fetch是基于promise设计的,
- 如果浏览器不支持promise,可以引入 es6-promise 或者 promise。
- 如果希望IE8也支持,可以参考 使用fetch遇到过的坑 或者使用 fetch-ie8
fetch参数
参考 Fetch Standard 或者 Using Fetch
上面你对fetch有基本的了解了,而且提供了不少的链接解惑,那么我们进入正题,whatwg-fetch源码分析
依旧是先删除无用的代码,
(function (self) { 'use strict'; if (self.fetch) { return } // 封装的 Headers,支持的方法参考https://developer.mozilla.org/en-US/docs/Web/API/Headers function Headers(headers) { ...... } //方法参考:https://developer.mozilla.org/en-US/docs/Web/API/Body function Body() { ...... } // 请求的Request对象 ,https://developer.mozilla.org/en-US/docs/Web/API/Request // cache,context,integrity,redirect,referrerPolicy 在MDN定义中是存在的 function Request(input, options) { ...... } Body.call(Request.prototype) //把Body方法属性绑到 Reques.prototype function Response(bodyInit, options) { } Body.call(Response.prototype) //把Body方法属性绑到 Reques.prototype self.Headers = Headers //暴露Headers self.Request = Request //暴露Request self.Response = Response //暴露Response self.fetch = function (input, init) { return new Promise(function (resolve, reject) { var request = new Request(input, init) //初始化request对象 var xhr = new XMLHttpRequest() // 初始化 xhr xhr.onload = function () { //请求成功,构建Response,并resolve进入下一阶段 var options = { status: xhr.status, statusText: xhr.statusText, headers: parseHeaders(xhr.getAllResponseHeaders() || '') } options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL') var body = 'response' in xhr ? xhr.response : xhr.responseText resolve(new Response(body, options)) } //请求失败,构建Error,并reject进入下一阶段 xhr.onerror = function () { reject(new TypeError('Network request failed')) } //请求超时,构建Error,并reject进入下一阶段 xhr.ontimeout = function () { reject(new TypeError('Network request failed')) } // 设置xhr参数 xhr.open(request.method, request.url, true) // 设置 credentials if (request.credentials === 'include') { xhr.withCredentials = true } else if (request.credentials === 'omit') { xhr.withCredentials = false } // 设置 responseType if ('responseType' in xhr && support.blob) { xhr.responseType = 'blob' } // 设置Header request.headers.forEach(function (value, name) { xhr.setRequestHeader(name, value) }) // 发送请求 xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) }) } //标记是fetch是polyfill的,而不是原生的 self.fetch.polyfill = true })(typeof self !== 'undefined' ? self : this); // IIFE函数的参数,不用window,web worker, service worker里面也可以使用
简单分析一下
- 如果自身支持fetch,直接返回,用自身的
- 内部核心 Headers, Body, Request, Response,
- Request和Resonse原型上有Body的方法属性,或者说,继承了
- Headers,Request ,Reponse暴露到全局
- fetch本质就是对XMLHttpRequest 请求的封装
这么一看其实到没什么了,不过完整代码里面有一些东西还是提一下(后面的参考都有链接)
- Symbol, Iterator : ES6里面很多集合是自带默认Iterator的,作用就是在 let...of,数组解构,新Set,Map初始化等情况会被调用。
- DataView , TypedArray:都是对TypeArray读写的API
- Blob,FileReader :File API,这个也没啥多说的
-
URLSearchParams: 这个支持度还不高,用来解析和构建 URL Search 参数的,例如 new URLSearchParams(window.location.search).get('a')
对外暴露的对象或者方法有
- fetch
封装过后的fetch,关于