url
:字符串类型,提交的网络地址data
:对象类型,提交的表单数据type
:提交的方法类型:GET或者POST,,默认为GETmethod
:使用的方法,function Ajax(url = '', data = {}, type = 'GET', method = 'fetch'){
// ...
}
如果请求提交的方式为GET,我们就需要将表单数据拼接成形如“a=12&b=10
”格式的字符串,并附加在url尾部。
如果请求提交的方式为POST,我们只需要使用JSON.stringify()
方法,将表单数据转换成JSON格式对象即可。
type = type.toUpperCase()
let sendData
if (type == 'GET') {
let _data = []
Object.keys(data).forEach(key => {
_data.push(key + '=' + data[key])
})
url = url + '?' + _data.join('&')
} else {
sendData = JSON.stringify(data)
}
Object.keys()
ES5引入的一个方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历的属相的键名。
我们可以使用Object.keys(data)
来获得表单数据对象所有可遍历的属性名数组。
arr.forEach()
用于遍历数组的成员
如果使用fetch
方法,需要浏览器支持fetch方法
fetch
JavaScript 通过XMLHttpRequest(XHR)来执行异步请求,这个方式已经存在了很长一段时间。虽说它很有用,但它不是最佳API。它在设计上不符合职责分离原则,将输入、输出和用事件来跟踪的状态混杂在一个对象里。而且,基于事件的模型与最近JavaScript流行的Promise以及基于生成器的异步编程模型不太搭(事件模型在处理异步上有点过时了——译者注)。
新的 Fetch API打算修正上面提到的那些缺陷。 它向JS中引入和HTTP协议中同样的原语(即Fetch——译者注)。具体而言,它引入一个实用的函数fetch()
用来简洁捕捉从网络上检索一个资源的意图。
Fetch 提供了对 Request 和 Response (以及其他与网络请求有关的)对象的通用定义。使之今后可以被使用到更多地应用场景中:无论是service workers、Cache API、又或者是其他处理请求和响应的方式,甚至是任何一种需要你自己在程序中生成响应的方式。
它还提供了一种定义,将 CORS 和 HTTP 原生的头信息结合起来,取代了原来那种分离的定义。
Fetch API是W3C的正式标准,被Firefox 39(Nightly版)以及Chrome 42(开发版)支持。在github上,有基于低版本浏览器的兼容实现
示例代码
// Simple response handling
fetch('/some/url').then(function(response) {
}).catch(function(err) {
// Error :(
});
// Chaining for more "advanced" handling
fetch('/some/url').then(function(response) {
return //...
}).then(function(returnedValue) {
// ...
}).catch(function(err) {
// Error :(
});
具体实现
let reqConfig = {
credentials: 'include',
method: type,
headers: {
'Accept': 'application/json',
'Content-type': 'application/json'
},
mode: 'cors',
cache: 'force-cache'
}
try {
const response = fetch(url, reqConfig)
const responseJson = response.json()
return responseJson
} catch(error) {
throw new Error(error)
}
如果使用传统的ajax方法
let reqObj
if (window.XMLHttpRequest) {
reqObj = new XMLHttpRequest()
} else {
reqObj = new ActiveXObject('Microsoft.XMLHTTP')
}
reqObj.open(type, url, true)
reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
reqObj.send(sendData)
reqObj.onreadystatechange = () => {
if (reqObj.readyState == 4) {
if (reqObj.status == 200) {
let res = reqObj.response
if (typeof res !== 'object') {
res = JSON.parse(res)
}
return res
} else {
return reqObj
}
}
}
####采用ES6异步编程解决方案
Promise
Promise是ES6标准中提供的一种异步编程解决方案。当我们采用异步的方式发出一个ajax请求之后,系统不会等待请求响应,而是继续往下执行。一般我们采用回调的方式,当收到服务端响应之后,系统才会执行相应的回调函数。
Promise简单来说就是一个容器,容器内部保存着某个未来才会执行的事件。
Promise内部维护着一个状态机,总共有三种状态:Pending(进行中)、Fulfilled(已完成)、Rejected(已失败)。我们可以使用reject()
和resolve()
来更改状态。
var promise = new Promise(function(resolve, reject) {
/// ...
if () { /* 如果异步操作执行成功 */
// 将Promise对象的状态从“未完成”变为“成功”
resolve(something)
} else {/* 否则异步操作执行失败 */
// 将Promise对象的状态从“未完成”变为“失败”
reject(something)
}
})
resolve和reject函数中的参数会自动传递给回调函数
promise.then(function(something) {
// ...
console.log(something)
})
我们可以采用链式then指定一组按照次序调用的回调函数
promise.then(function(something1) {
// ...
return promise(something2)
}).then(function(something2) {
})
因此,ajax异步处理过程可以改写为
return new Promise((resolve, reject) => {
let reqObj
if (window.XMLHttpRequest) {
reqObj = new XMLHttpRequest()
} else {
reqObj = new ActiveXObject('Microsoft.XMLHTTP')
}
reqObj.open(type, url, true)
reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
reqObj.send(sendData)
reqObj.onreadystatechange = () => {
if (reqObj.readyState == 4) {
if (reqObj.status == 200) {
let res = reqObj.response
if (typeof res !== 'object') {
res = JSON.parse(res)
}
resolve(res)
} else {
reject(reqObj)
}
}
}
})
async
ES2017标准引入了async
函数,使得异步操作变得更加方便。async
函数会返回一个Promise对象。
async function getUserInfo(userid){
let userinfo = await getJson(...)
return userinfo
}
await命令后面是一个Promise对象,如果不是,会被转成一个resolve的Promise对象
####完整代码
async function Ajax(url = '', data = {}, type = 'GET', method = 'fetch'){
// 整理表单数据
type = type.toUpperCase()
let sendData
if (type == 'GET') {
let _data = []
Object.keys(data).forEach(key => {
_data.push(key + '=' + data[key])
})
url = url + '?' + _data.join('&')
} else {
sendData = JSON.stringify(data)
}
// 创建ajax提交对象
if (window.fetch && method == 'fetch') {
let reqConfig = {
credentials: 'include',
method: type,
headers: {
'Accept': 'application/json',
'Content-type': 'application/json'
},
mode: 'cors',
cache: 'force-cache'
}
try {
const response = await fetch(url, reqConfig)
const responseJson = await response.json()
return responseJson
} catch(error) {
throw new Error(error)
}
} else {
return new Promise((resolve, reject) => {
let reqObj
if (window.XMLHttpRequest) {
reqObj = new XMLHttpRequest()
} else {
reqObj = new ActiveXObject('Microsoft.XMLHTTP')
}
reqObj.open(type, url, true)
reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
reqObj.send(sendData)
reqObj.onreadystatechange = () => {
if (reqObj.readyState == 4) {
if (reqObj.status == 200) {
let res = reqObj.response
if (typeof res !== 'object') {
res = JSON.parse(res)
}
resolve(res)
} else {
reject(reqObj)
}
}
}
})
}
}
export default async(url = '', data = {}, type = 'GET', method = 'fetch'){
// 整理表单数据
type = type.toUpperCase()
let sendData
if (type == 'GET') {
let _data = []
Object.keys(data).forEach(key => {
_data.push(key + '=' + data[key])
})
url = url + '?' + _data.join('&')
} else {
sendData = JSON.stringify(data)
}
// 创建ajax提交对象
if (window.fetch && method == 'fetch') {
let reqConfig = {
credentials: 'include',
method: type,
headers: {
'Accept': 'application/json',
'Content-type': 'application/json'
},
mode: 'cors',
cache: 'force-cache'
}
try {
const response = await fetch(url, reqConfig)
const responseJson = await response.json()
return responseJson
} catch(error) {
throw new Error(error)
}
} else {
return new Promise((resolve, reject) => {
let reqObj
if (window.XMLHttpRequest) {
reqObj = new XMLHttpRequest()
} else {
reqObj = new ActiveXObject('Microsoft.XMLHTTP')
}
reqObj.open(type, url, true)
reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
reqObj.send(sendData)
reqObj.onreadystatechange = () => {
if (reqObj.readyState == 4) {
if (reqObj.status == 200) {
let res = reqObj.response
if (typeof res !== 'object') {
res = JSON.parse(res)
}
resolve(res)
} else {
reject(reqObj)
}
}
}
})
}
}
我们可以在使用的时候引入ajax模块
import ajax from 'ajax'
// 查询user_id为1的用户信息
ajax('/users', {
user_id: 1
}).then(res => {
console.log(res.username)
})