Web开发领域一直在不断演进,特别是在异步请求方面。传统的Ajax通信主要依赖于XMLHttpRequest(XHR),然而,现在已经有了一种更现代、更简洁的替代方案------Fetch API。本文将探讨XMLHttpRequest面临淘汰的趋势,Fetch API作为替代方案的优势,以及关注一个优秀的请求库------umi-request。
1. 传统Ajax(XMLHttpRequest)的弊端
在过去,使用XHR进行异步请求是很常见的做法,但这个API设计相对粗糙,不符合关注分离的原则。XHR的配置和调用方式混乱,而且基于事件的异步模型在处理复杂逻辑时显得不够友好。
2. Fetch API的优势
2.1 语法简洁,更具语义化
Fetch API的语法相较于XHR更为简洁,并更具有语义化。通过一些简单的示例可以清晰地看出,使用Fetch API进行json请求相对于XHR的写法更加清晰:
ini
javascriptCopy code
// 使用XHR
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(response => response.json())
.then(data => console.log(data))
.catch(e => console.log("Oops, error", e));
2.2 支持Promise、async/await
Fetch API是基于Promise设计的,支持使用Promise的链式调用,而且可以轻松地结合使用async/await,使异步代码的编写更为流畅。这种现代化的异步处理方式相较于XHR的事件模型更为友好。
javascript
javascriptCopy code
// 使用async/await
try {
let response = await fetch(url);
let data = await response.json();
console.log(data);
} catch(e) {
console.log("Oops, error", e);
}
2.3 同构方便
Fetch API非常适合构建同构应用,即前后端运行同一套代码。一些基于Fetch的语法的库,如node-fetch和isomorphic-fetch,使得在Node环境中也能方便地使用Fetch。
3. umi-request库的介绍
为了更方便地使用Fetch API,许多优秀的请求库涌现。其中,umi-request是一款由阿里出品的请求库,经过阿里巨量PV数据产品的验证,证明在生产环境中使用Fetch是可行的。
3.1 Fetch polyfill的支持
umi-request使用了一系列polyfill,如es5-shim、es5-sham、es6-promise等,以确保在低版本浏览器中也能完美支持Fetch API。
3.2 IE的兼容性策略
对于不支持原生Fetch的IE浏览器,umi-request会自动使用XHR进行polyfill。在跨域时,umi-request也处理了IE8和IE9 XHR不支持CORS跨域的问题,为使用者提供了更好的兼容性。
4. Fetch的常见坑和解决方案
在使用Fetch时,需要注意一些常见的问题:
4.1 默认不携带cookie
Fetch请求默认是不携带cookie的,需要设置{credentials: 'include'}。
4.2 不会reject服务器返回的400、500错误
当服务器返回400或500错误码时,并不会导致Fetch被reject,只有网络错误才会触发reject。需要开发者手动处理服务器返回的错误码。
4.3 兼容性处理
在处理兼容性时,需要引入一系列polyfill,确保在各类浏览器中都能正常使用Fetch。
5. Fetch的优势进一步探讨
5.1 更好的异步处理
除了语法简洁、Promise支持等优势外,Fetch API在异步处理方面还有其他显著的改进。相比于XMLHttpRequest的事件模型,Fetch更灵活,可以轻松地处理多个并发请求,而不需要陷入回调地狱的情况。
ini
javascriptCopy code
// 处理多个并发请求
Promise.all([
fetch(url1),
fetch(url2),
fetch(url3)
])
.then(responses => {
// 处理所有请求的响应
return Promise.all(responses.map(response => response.json()));
})
.then(dataArray => {
// 处理各个请求的返回数据
console.log(dataArray);
})
.catch(error => console.log("Oops, error", error));
5.2 支持CORS(跨域资源共享)
Fetch API天生支持跨域资源共享,无需额外设置。而在XMLHttpRequest中,跨域请求必须通过设置withCredentials和服务端设置响应头的方式来实现,相对繁琐。
ini
javascriptCopy code
// Fetch中的跨域请求
fetch(url, { credentials: 'include' })
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log("Oops, error", error));
// XMLHttpRequest中的跨域请求
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.withCredentials = true;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send();
6. Fetch常见坑的更多细节
6.1 请求中断和超时处理
由于Fetch和Promise一样,一旦发起请求就不能中断,也没有超时机制。然而,目前Fetch的规范正在尝试解决这个问题,讨论中的提案whatwg/fetch#27希望能够引入中断请求的能力。
6.2 Fetch的缺失功能
尽管Fetch API在语法和设计上有很多优势,但在某些功能上仍然存在缺失。例如,它没有像XHR那样的abort、terminate、onTimeout或cancel方法,使得在某些特定场景下的处理相对受限。此外,Promise的功能相对简洁,缺少了一些像always、progress、finally等方法,需要通过其他手段实现。
7. 异步编程的未来展望
随着ES6的Promise、generator/yield、ES7的async/await等新异步语法的出现,异步编程在JavaScript中变得更加流畅。标准的Promise逐渐替代了第三方的Promise库,而使用polyfill是一个明智的选择,为全面使用async/await做好准备。
8. 结论
在Web开发的进程中,Fetch API作为XMLHttpRequest的现代替代方案,呈现出语法简洁、更好的异步处理、支持CORS等优势。在实际应用中,借助优秀的请求库如umi-request,可以更好地解决兼容性问题,提升开发效率。虽然在使用中会遇到一些坑,但通过了解这些问题并选择合适的工具,我们可以更好地利用Fetch API进行异步请求,为Web开发带来更为便捷、现代化的体验。异步编程的未来将更为光明,带给开发者更多便利和可能性。