Javascript语言将任务的执行模式分红两种:同步(Synchronous)和异步(Asynchronous)。vue
在浏览器,耗时很长的操做都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操做。经过XHRHttpRequest对象及时监听完成事件,执行事件回调函数不会堵塞程序运行。jquery
Fetch API 提供了一个 JavaScript接口,用于访问和操纵HTTP管道的部分,例如请求和响应。它还提供了一个全局 fetch()方法,该方法提供了一种简单,合乎逻辑的方式来跨网络异步获取资源。这种功能之前是使用 XMLHttpRequest实现的。Fetch提供了一个更好的替代方法,能够很容易地被其余技术使用,例如 Service Workers。Fetch还提供了单个逻辑位置来定义其余HTTP相关概念,例如 CORS和HTTP的扩展。web
新的Fetch API是XHRHttpRequest异步请求的另外一种方案,比起其复杂糅杂的写法,fetch能更简洁的获取到数据。ajax
XHRHttpRequest使用事件回调函数容易进入回调地狱,而Fetch Api接收url参数返回Promise对象。json
Fetch 提供了对 Request 和 Response (以及其余与网络请求有关的)对象的通用定义。使之从此能够被使用到更多地应用场景中api
let url = 'http://jsonplaceholder.typicode.com/users' fetch(url).then((res)=>{ console.log(res) }).catch((err)=>{})
将url传递给fetch时会当即返回一个promise对象此时的状态是pending,当promise被经过时会返回一个response对象。若是咱们用习惯了好比jquery封装好的ajax方法,很容易会觉得上面的res就是返回的data。跨域
fetch 只有在遇到网络错误的时候才会 reject 这个 promise,好比用户断网或请求地址的域名没法解析等。只要服务器可以返回 HTTP 响应(甚至只是 CORS preflight 的 OPTIONS 响应),promise 必定是 resolved 的状态。promise
fetch返回Promise对象浏览器
response.type有如下几种缓存
basic 标准值,同源响应
cors 收到一个有效的跨域请求
opaque 跨域请求但服务器没有返回cors响应头
可是无效的跨域请求若是像下面这么写,其实根本没法拿到response对象
request.mode用于肯定跨域请求是否致使有效的响应
same-origin 同源状况下才可请求成功,不然抛出错误
好比在有效的跨域请求设置这个模式会提示
Fetch API cannot load http://jsonplaceholder.typico... Request mode is "same-origin" but the URL's origin is not same as the request origin file://.
cors: 表示同域和带有CORS响应头的跨域下可请求成功.
cors-with-forced-preflight: 表示在发出请求前, 将执行preflight检查.
no-cors: 用于跨域相应不带cors的状况,此时相应类型为opaque
根据上面的错误修改fetch的模式就能够返回response对象了,能够对比发现无效跨域请求并无返回什么有价值的信息例如url,status,statusText等
reponse.body属于ReadableStream类型
当读取CSV等大文件时经过流来读取,能够选择在读取到要获取的数据后中止流,而不是获取到所有响应数据再去查找。
对于经常使用返回的几种数据类型,可使用blob()、text()、formData()、json(),这几种方法都会讲body标记为已读数据,因此想再次获取的时候就会报错
好比下面的代码,真实返回的数据不是json类型的,想利用catch方法去捕获而后再次返回text类型,浏览器时会报TypeError: Already read
fetch(url).then(function(response) { return response.json().catch(function() { return response.text(); }); });
正确的方式是使用clone()方法先对数据进行拷贝,响应数据经过clone并不会被回收,一直留在内存中,直至被读取
fetch(url).then(function(response) { return response.clone().json().catch(function() { return response.text(); }); });
method:设置请求方法,默认GET方法
credentials fetch方法默认不发送cookies,若是遇到401 Unauthorized没有权限问题就要看看是否有设置credentials
omit: 从不发送cookies.
same-origin: 只有当URL与响应脚本同源才发送cookies.
include: 老是发送cookies, 即便来自跨域的请求
默认状况下请求不带coookie
cache 设置缓存,跟XHR对比在请求时就能够控制缓存,虽然这是有争议的,由于这暴露了用户历史记录
default
若是是最新的资源,则返回缓存
若是资源已过时则向服务器发出条件请求;若是服务器指示资源没有改变则返回缓存;不然从服务器中下载,并更新缓存。
若是没有找到缓存则发出正常情求,但不缓存资源。
no-store 直接从服务器获取资源而且不会将资源缓存
reload 直接从服务器获取资源,而且缓存资源
no-cache
若是资源有效或者过时,浏览器会发出一个条件请求,若是服务器返回没有改变,则返回缓存,不然,从新获取资源并更新缓存
若是不存在资源则浏览器发出正常请求下载并更新缓存
force-cache
若是有缓存直接返回缓存,不然下载更新资源
only-if-cached
若是有缓存直接返回缓存,不然浏览器返回错误
fetch没有xhr中的abort()方法来中断请求
fetch没有progress进度事件监听数据,可是你能够经过获取content-length计算进度
XHR open方法有最后一个参数设为false的时候是同步请求,fetch没有提供同步请求的方法,但同步请求并不经常使用
fetch 并无像XHR的timeout属性来设置延时
习惯了像是vue-resource等插件封装好的get,post方法,在使用fetch的时候很容易会被它看似简洁的api给迷惑
fetch兼容性问题
咱们须要引入fetch 的polyfill,扒开源码咱们能够发现实现原理仍是创建在XMLHttpRequest上的,可是因为polyfill要实现fetch如Blob类文件对象等,在safari和ie上仍是有兼容性问题的
参数传递问题
在get请求方式中,咱们仍是只能像xhr那样以拼接url字符串的方式来传递,这与fetch看起来简洁的api有点不符。
虽然原生的URLSearchParams 接口定义了用来处理 URL 参数串的方法。可是这个api目前兼容性也是不怎么好
var paramsString = "q=URLUtils.searchParams&topic=api"
var searchParams = new URLSearchParams(paramsString);
searchParams.append("topic", "webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
在post请求中,数据要以body字段来传递参数,也就是说咱们要经常使用的json格式要通过下面格式的转换,就像XMLHttpRequest那样
body 能够是如下任何一种类型的实例:
ArrayBuffer ArrayBufferView (Uint8Array and friends) Blob/File string URLSearchParams FormData
响应数据的问题
在回调函数中咱们首先接受到的是response对象,因为body是ReadableStream类型,几乎很难预先判断数据是什么类型,也就很难判断是到底用text()、json()方法解析数据
response对象有一个bodyUsed的属性初始是false,调用text()、json()等方法会读取Response对象而且将它设置为已读,这时bodyUsed为true
bodyUsed初始值为false
- 解决办法有两种但都有必定的不足 1.是经过clone加catch方式找到正确的输出方式,可是要注意调用方法的顺序,否则一个json有可能最后仍是以text的方式解析,还要注意的是最后要将response的数据回收或者读取,由于clone方法的读取并不影响原来的reponse对象
fetch(url).then(function(response) { return response.json().catch(function() { return response.text(); }); });
2.是经过判断content-type的方式,若是已知的返回格式很少的状况下用仍是不错的选择
fetch(url).then(function(response) { if (response.headers.get('Content-Type') === 'application/json') { return response.json(); } return response.text(); });
基于promise的fecth方法可让咱们远离回调地狱而不须要其余的封装。
fetch 将 response.body 设计成 ReadableStream 实际上是很是有前瞻性的,这种设计让你在请求大致积文件时变得很是有用。