JavaScript异步编程之XHR与fetch

我的github github.com/zhuanyongxi…

AJAX模型

图片左侧的部分是有AJAX之前的浏览器与服务器交互的方式,是同步的,发出请求之后需要等待,这样的体验就非常不好。AJAX的出现改变了这一情况,由不同变成了异步,发出请求之后不再需要等待。

XHR

这是最通用的AJAX的API,完整的写法是XMLHttpRequest。虽然名字里面有XML,可它所支持的数据类型不只是XML。

常用的几步:

var xhr = new XMLHttpRequest();
console.log('UNSENT', xhr.readyState);	// readyState will be 0

xhr.open('GET', '/api', true);
console.log('OPENED', xhr.readyState);	// readyState will be 1

xhr.onprogress = function() {
  console.log('LOADING', xhr.readyState);	// readyState will be 3
};
xhr.onreadystatechange = function() {
  if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
    console.log(xhr.responseText);
  }
};
xhr.onload = function() {
  console.log('DONE', xhr.readyState);	// readyState will be 4
}
复制代码

你肯定在想我这是从哪抄的代码吧?从MDN上抄的,链接是这个。其中open这个api的第三个参数默认值是true,也就是异步,false就是同步。通常都是使用异步。另外还要知道一些常用的http的状态码如:200、301、302、304、400、401、404、500、501。

fetch

与XHR相比,fetch基于promise,写法更加简洁优雅,它可以更好的支持更多的场景,如service workers、Cache API等。

相信很多人也都用过axios,与axios相比,fetch这个api,总结一下就是:好用的功能都需要自己写。比如拦截器,自动转换数据格式等。不过这本身也没什么比较的必要,因为他们的定位不同,fetch是js的api,编程语言的api,肯定会做的很基础,目光放的更长远;而axios是一个第三方的方法库,它存在的意义就是在现有api的基础上做一次封装,增加一些好用的方法,不过axios封装的是XHR,并不是fetch。

再抄一波代码,对比fetch与XHR:

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

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

xhr.onerror = function() {
  console.log("Booo");
};

xhr.send();
复制代码

同样的需求用fetch写:

fetch(url).then(function(response) {
  return response.json();
}).then(function(data) {
  console.log(data);
}).catch(function() {
  console.log("Booo");
});
复制代码

在加上ES6的箭头函数:

fetch(url).then(r => r.json())
  .then(data => console.log(data))
  .catch(e => console.log("Booo"))
复制代码

简单多了吧?

不过这里有一个需要注意的地方,fetch只有遇到网络错误或服务端cors未配置的时候才会reject,就是说像500、404这样的错误,fetch是不会reject的。解决方法就是用response.ok

fetch("http://httpstat.us/500")
  .then(function(response) {
    if (!response.ok) {
      throw Error(response.statusText);
    }
    return response;
  }).then(function(response) {
    console.log("ok");
  }).catch(function(error) {
    console.log(error);
  });
复制代码

一个可以参考的对fetch的简单的封装:

const options = {
  headers: new Headers({'Content-Type': 'application/json'}),
  cache: 'default',
  method: 'GET',
  mode: 'cors'
}

function get(url, params) {
  const opts = Object.assign({}, options, {method: 'GET'});
  return fetch(`${url}?${querystring.stringify(params)}`, opts)
    .then(data => data.json());
}

function post(url, params) {
  const opts = Object.assign({}, options, {method: 'POST', body: JSON.stringify(params)});
  return fetch(url, opts)
    .then(data => data.json());
}
复制代码

这一段也是抄的,但我不告诉你我是在哪抄的。

使用fetch需要注意的几个地方

  • 默认不带cookie,自己加;

    fetch(url, {
      credentials: 'include'
    })
    复制代码
  • 不支持同步;

  • 不支持取消;

  • 无法查看请求进度。

参考资料:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值