最近剛入手promise封裝網路請求,說說封裝思路:
先封裝一個ajax請求 => 再用promise 進行封裝 => 配置攔截器(interceptors)=> 再設定實體install方法(vue插件形式);
廢話不多說,貼上代碼如下:
/*一、ajax封裝*/
const data = {}
_ajax(config,cb) {
data.config = config = utils.merge(this.defaults, config)
// 1、創建HTTP請求實體
let xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP')
// request攔截點1,可配置請求根域名
if (config.method.toUpperCase() === 'GET' && config.data) {
config.url = config.url + '?' + utils.serialize(config.data)
config.data = null
}
//2、打開請求 開始配置
xhr.open(config.method, config.url, config.async)
if (isPOST(config.method)) {
config.data = JSON.stringify(config.data)
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
}
// request攔截點2,可配置請求頭 攜帶引數
//3、發送資料
xhr.send(config.data)
//4、回應完成回呼獲取資料
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
data.status = xhr.status
data.xhr = xhr
if (isGetFullData(xhr)) {
data.data = JSON.parse(xhr.responseText)//data為回應的物件格式
xhr = null
/* response 回應攔截點1、回應成功*/
cb(data)
} else {
/* response 回應攔截點2、回應失敗*/
cb(xhr.status)
}
}
}
}
/*二、用promise封裝(這封裝get,post簡介版)*/
get(url, data) {
return new Promise((resolve, reject) => {
const opt = {
url, data
}
_ajax(opt, resolve, reject)
})
}
post(url, data,config) {
return new Promise((resolve, reject) => {
const opt = {
url, data, method: 'POST'
}
for(let k in config){
opt[k] = config[k];
}
_ajax(opt, resolve, reject)
})
}
當然上面的_ajax方法要改進一下了,如下:
_ajax(config, resolve, reject) {
data.config = config = utils.merge(this.defaults, config)
// 1、創建HTTP請求實體
let xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP')
// request攔截點1,可配置請求根域名(呼叫open方法需要URL引數,所以URL必須在open呼叫前配置)
if (config.method.toUpperCase() === 'GET' && config.data) {
config.url = config.url + '?' + utils.serialize(config.data)
config.data = null
}
//2、打開請求 開始配置
xhr.open(config.method, config.url, config.async)
if (isPOST(config.method)) {
config.data = JSON.stringify(config.data)
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
}
// request攔截點2,呼叫open方法后,才可配置請求頭 攜帶引數
//3、發送資料
xhr.send(config.data)
const self = this
//4、回應完成回呼獲取資料
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
data.status = xhr.status
data.xhr = xhr
if (isGetFullData(xhr)) {
data.data = JSON.parse(xhr.responseText)
xhr = null
/* response 回應攔截點1、回應成功*/
if (self.interceptors.cb) {
/*這是一個回應完成資料攔截點*/
} else {
resolve(data)
}
} else {
/* response 回應攔截點2、回應失敗*/
if (self.interceptors.cbError) {
/**回應超時攔截點(斷網或服務器出錯)/
} else {
reject(new Error('Request was unsuccessful: ' + xhr.status))
}
}
}
}
}
三、添加攔截器
說到攔截器主要就以上4點,
request:1、open前URL配置;
2、open后請求頭配置及請求超時配置;
response:readyState===4時,也就是回應完成時,截取資料、例外做進一步處理
好了,繼續貼上攔截器類代碼,如下:
/**
* 攔截器類
*/
class Interceptors {
request = {
use(cb, cbError) {
axios.defaults = cb(axios.defaults)
typeof cbError === 'function' && cbError('error')
}
}
interceptor = { readyState: 0 }
response = {
use(cb, cbError) {
if (typeof cb === 'function') axios.interceptors.cb = true
if (typeof cbError === 'function') axios.interceptors.cbError = true
axios.cb = cb
axios.cbError = cbError
if (interceptor && interceptor.readyState === 4) {
let xhr = data.xhr
if (isGetData(xhr)) {
cb(data).then((res) => {
this.resolve(res)
// data=https://bbs.csdn.net/topics/null
}).catch((error) => {
this.reject(error)
})
} else {
cbError(xhr.status).catch((error) => {
this.reject(new Error('Request was unsuccessful:' + error))
})
}
}
},
run(resolve, reject) {
this.resolve = resolve
this.reject = reject
interceptor.readyState = 4
}
}
}
加上攔截器后,_ajax方法還得改進一下,不過已經差不多了,直接貼上終極代碼,如下:
/**
* 工具類
*/
const utils = {
/**
* 序列化資料成:key=value&key=value字串
* @param {*} o 資料物件
*/
serialize(o) {
let params = []
for (let k in o) {
params.push(k + '=' + o[k])
}
return params.join('&')
},
forEach(obj, fn) {
if (obj === null || typeof obj === 'undefined') {
return
}
if (typeof obj !== 'object') {
obj = [obj]
}
for (let k in obj) {
if (hasOwn(obj, k)) {
fn(obj[k], k, obj)
}
}
},
/* 合并函式 */
merge(/* obj1, obj2, obj3, ... */) {
let result = {}
function assignValue(val, key) {
if (typeof result[key] === 'object' && typeof val === 'object') {
result[key] = utils.merge(result[key], val)
} else {
result[key] = val
}
}
for (let i = 0, l = arguments.length; i < l; i++) {
this.forEach(arguments[i], assignValue)
}
return result
}
}
/**
* 觀察者函式
* @param {*} obj 被觀察物件
*/
function ob(obj) {
if (!isObject(obj)) {
return
}
const handler = {
get(target, key) {
return target[key]
},
set(target, key, value) {
target[key] = value
isResponseComplete(key, value) && axios.interceptors.response.use(axios.cb, axios.cbError)
return true
}
}
return new Proxy(obj, handler)
}
/**
* 判斷物件o是否有k屬性
* @param {*} o 物件
* @param {*} k 屬性
*/
function hasOwn(o, k) {
return Object.prototype.hasOwnProperty.call(o, k);
}
/**
* 判斷回應是否完成(readyStatus===4)
* @param {*} key 屬性
* @param {*} val 值
*/
function isResponseComplete(key, val) {
return key === 'readyState' && val === 4
}
/**
* v是否為物件
* @param {*} v
*/
function isObject(v) {
return v && Object.prototype.toString.call(v) === '[object Object]'
}
/**
* 請求是否獲得完整資料
* @param {*} xhr 請求物件實體
*/
function isGetFullData(xhr) {
return (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304
}
/**
* method是否為POST
* @param {*} method
*/
function isPOST(method) {
return method.toUpperCase() === 'POST'
}
/* 攔截請求狀態readyState===4(回應完成時)*/
let interceptor = null
/*回傳物件資料*/
const data = {}
/* 攔截器類*/
class Interceptors {
request = {
use(cb, cbError) {
axios.defaults = cb(axios.defaults)
typeof cbError === 'function' && cbError('error')
}
}
interceptor = { readyState: 0 }
response = {
use(cb, cbError) {
if (typeof cb === 'function') axios.interceptors.cb = true
if (typeof cbError === 'function') axios.interceptors.cbError = true
axios.cb = cb
axios.cbError = cbError
if (interceptor && interceptor.readyState === 4) {
let xhr = data.xhr
if (isGetData(xhr)) {
cb(data).then((res) => {
this.resolve(res)
}).catch((error) => {
this.reject(error)
})
} else {
cbError(xhr.status).catch((error) => {
this.reject(new Error('Request was unsuccessful:' + error))
})
}
}
},
run(resolve, reject) {
this.resolve = resolve
this.reject = reject
interceptor.readyState = 4
}
}
}
/*Axios請求類 */
class Axios {
constructor(config) {
this.defaults = config
this.interceptors = new Interceptors()
}
get(url, data) {/*省略*/}
post(url, data,config) {/*省略*/}
_ajax(config, resolve, reject) {
data.config = config = utils.merge(this.defaults, config)
// 1、創建HTTP請求實體
let xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft.XMLHTTP')
interceptor = ob(this.interceptors.interceptor)
// request攔截點1,可配置請求根域名
this.defaults && (config.url = config.baseURL + config.url)
if (config.method.toUpperCase() === 'GET' && config.data) {
config.url = config.url + '?' + utils.serialize(config.data)
config.data = null
}
//2、打開請求 開始配置
xhr.open(config.method, config.url, config.async)
isPOST(config.method) && (config.data = JSON.stringify(config.data))
// request攔截點2,可配置請求頭 攜帶引數
if (config.headers) {
for (let k in config.headers) {
xhr.setRequestHeader(k, config.headers[k])
}
if (!hasOwn(config.headers, 'Content-Type') && isPOST(config.method)) {
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
}
}
config.timeout&&(xhr.timeout = config.timeout)
//3、發送資料
xhr.send(config.data)
const self = this
//4、回應完成回呼獲取資料
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
data.status = xhr.status
data.xhr = xhr
if (isGetFullData(xhr)) {
data.data = JSON.parse(xhr.responseText)
xhr = null
/* response 回應攔截點1、回應成功*/
self.interceptors.cb?self.interceptors.response.run(resolve, reject):resolve(data)
} else {
/* response 回應攔截點2、回應失敗*/
self.interceptors.cbError?self.interceptors.response.run(resolve, reject)
:reject(new Error('Request was unsuccessful: ' + xhr.status))
}
}
}
}
/**
* 配置請求資訊
* @param {*} config
*/
create(config) {
this.defaults = utils.merge(this.defaults, config)
return this
}
}
/* 默認請求配置*/
const config = {
method: 'GET',
baseURL: '',
url: '',
async: true,
data: null
}
/* Axios請求實體*/
const axios = new Axios(config)
axios.install = Vue => Vue.prototype.$http = axios
export default axios
考慮的不全面,有問題歡迎來懟
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/123059.html
標籤:Ajax
上一篇:亂數做軟鍵盤
