-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
自入行前端一来各种项目里有很多 Ajax 应用案例,大多数情况下都考虑了用 axios 等库来实现需求,直到打包的时候才 WTF,为什么一个简简单单的 Ajax 需求要耗费我几十 KB 的打包空间?
本文先以兼容性较好的 XMLHttpRequest (Level 2) 标准入手,一步步打造符合自己使用需求的Ajax库。
背景知识
首先,请大家阅读上述两篇文章,掌握XMLHttpRequest的常用属性和方法。
接下来的阅读我将默认您已经会用XMLHttpRequest啦。
兼容性
一些后期需要 polyfill 的功能点
- IE8/IE9、Opera Mini 完全不支持xhr对象
- IE10/IE11部分支持,不支持 xhr.responseType为json
- 部分浏览器不支持设置请求超时,即无法使用xhr.timeout
- 部分浏览器不支持xhr.responseType为blob
实现思路
配置参数
首先确定需要参数化的一些配置属性
- url: 目标地址, 必须
- headers: 请求头属性对象 -
{header_name: header_value, ...} - body:
- string化的参数序列 ('application/x-www-form-urlencoded'较为常用,备选)
- FormData (未设置 Content-Type 的默认值)
- method: 'GET', 'POST', etc.
- cors: If your using cross-origin, you will need this true for IE8-9
回调函数参数
确定回调函数参数
- statusCode
- null or 0,考虑异常
- response
- 根据 Content-Type 输出对象
- 或者中断后输出 "Abort"
- 或者超时后输出 "Timeout"
- 或者其他错误输出 "Error"
代码
// xhr合法属性
var reqfields = [
'responseType', 'withCredentials', 'timeout', 'onprogress'
]
const ajax = function (params, callback) {
var headers = params.headers || {}
, body = params.body
, method = params.method || (body ? 'POST' : 'GET')
, called = false
// xhr对象generate
var req = getRequest(params.cors)
// 回调函数规范输出
function cb(statusCode, responseText) {
return function () {
if (!called) {
callback(req.status === undefined ? statusCode : req.status,
req.status === 0 ? "Error" : (req.response || req.responseText || responseText),
req)
called = true
}
}
}
req.open(method, params.url, true)
var success = req.onload = cb(200)
req.onreadystatechange = function () {
if (req.readyState === 4) success()
}
req.onerror = cb(null, 'Error')
req.ontimeout = cb(null, 'Timeout')
req.onabort = cb(null, 'Abort')
if (body) {
// 却省设置 FormData => 'application/x-www-form-urlencoded'
if (!window.FormData || !(body instanceof window.FormData)) {
setDefault(headers, 'Content-Type', 'application/x-www-form-urlencoded')
}
}
// xhr对象属性配置
for (var i = 0, len = reqfields.length, field; i < len; i++) {
field = reqfields[i]
if (params[field] !== undefined)
req[field] = params[field]
}
// xhr对象header配置
for (var field in headers)
req.setRequestHeader(field, headers[field])
req.send(body)
return req
}
function getRequest(cors) {
// IE 8 and 9 polifill
if (cors && window.XDomainRequest && !/MSIE 1/.test(navigator.userAgent))
return new XDomainRequest
if (window.XMLHttpRequest)
return new XMLHttpRequest
}
function setDefault(obj, key, value) {
obj[key] = obj[key] || value
}Demo
ajax({
method: 'GET',
responseType: 'json',
url: 'https://cnodejs.org/api/v1/topics',
headers: {
'Content-Type': 'application/json'
}
}, function (code, responseText) {
console.log(code)
console.log(responseText)
})
{
"success": true,
"data": [ ... ] // 40 Items
}
