【前端面试】手写Ajax
浏览器需要与服务器进行通信,这个过程是用ajax实现的。
借用一下W3School的描述:
原生JS手写Ajax
丐版(精简版)
//将query对象变成可以用在url里的字符串
function obj2Query(queryObj) {
let temp = []
for (key in queryObj) {
tmp.push(`${encodeURIComponent(key)}=${encodeURIComponent(queryObj[key])}`)
}
return temp.join('&')
}
function myAjax(url, queryObj, success, error) {
queryObj = queryObj || {} //防止queryObj === undefined
url += '?' + obj2Query(queryObj) //根据queryObj拼接出完整的url
//1. 定义一个xhr
const xhr = new XMLHttpRequest();
//2. 开启这个xhr请求,并定义methods,是否异步等信息(默认是true,即异步)
xhr.open('GET', url, true)
//3. 绑定onreadystatechange
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300 || xhr.status === 304) {
success(xhr.responseText) //具体返回什么看success函数要什么了
} else {
error(xhr.status) //具体返回什么看error函数要什么了
}
}
}
//4. 发送请求
xhr.send(null) //由于是get请求不传数据,所以是null
}
简单测试一下:
<div id="app"></div>
const app = document.getElementById("app")
const li = document.createElement('li')
myAjax('./test.json', { name: "zhangsan" },
(data) => {
li.innerHTML = data
app.appendChild(li)
},
(reason) => {
alert(reason)
})
设置超时版
//将query对象变成可以用在url里的字符串
function obj2Query(queryObj) {
let temp = []
for (key in queryObj) {
temp.push(`${encodeURIComponent(key)}=${encodeURIComponent(queryObj[key])}`)
}
return temp.join('&')
}
function myAjax(url, queryObj, success, error, timeout) {
queryObj = queryObj || {} //防止queryObj === undefined
url += '?' + obj2Query(queryObj) //根据queryObj拼接出完整的url
//设置一个timer
let timer;
//1. 定义一个xhr
const xhr = new XMLHttpRequest();
//2. 开启这个xhr请求,并定义methods,是否异步等信息(默认是true,即异步)
xhr.open('GET', url, true)
//3. 绑定onreadystatechange
xhr.onreadystatechange = function () {
if (timer) clearTimeout(timer)
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300 || xhr.status === 304) {
success(xhr.responseText) //具体返回什么看success函数要什么了
} else {
error(xhr.status) //具体返回什么看error函数要什么了
}
}
}
//4. 发送请求
xhr.send(null) //由于是get请求不传数据,所以是null
//5. 设置超时
if (timeout) {
timer = setTimeout(() => {
alert('ajax请求超时!')
xhr.abort()
}, timeout)
}
}
简单测试一下:
<div id="app"></div>
const app = document.getElementById("app")
const li = document.createElement('li')
myAjax('./test.json', { name: "zhangsan" },
(data) => {
li.innerHTML = data
app.appendChild(li)
},
(reason) => {
alert(reason)
}, 2000)
promise版
promise版就不传入success
和error
两个回调函数了,把它们放到then()
和catch()
里。
function obj2Query(queryObj) {
let temp = []
for (key in queryObj) {
temp.push(`${encodeURIComponent(key)}=${encodeURIComponent(queryObj[key])}`)
}
return temp.join('&')
}
function myAjax(url, queryObj, timeout = 2000) {
const promise = new Promise((resolve, reject) => {
queryObj = queryObj || {} //防止queryObj === undefined
url += '?' + obj2Query(queryObj) //根据queryObj拼接出完整的url
//1. 定义一个xhr
let timer
const xhr = new XMLHttpRequest();
//2. 开启这个xhr请求,并定义methods,是否异步等信息(默认是true,即异步)
xhr.open('GET', url, true)
//3. 绑定onreadystatechange
xhr.onreadystatechange = function () {
clearTimeout(timer)
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status <= 300 || xhr.status === 304) {
resolve(xhr.responseText) //具体返回什么看then要什么了
} else {
reject(`status code is ${xhr.status}`) //具体返回什么看catch要什么了
}
}
}
//4. 发送请求
xhr.send(null) //由于是get请求不传数据
//5. 设置超时
if (timeout) { //如果传入了timeout参数
timer = setTimeout(() => {
console.log('xhr timeout')
xhr.abort()
}, timeout)
}
})
return promise
}
简单进行一下测试:
<div id="app"></div>
首先是返回成功的情况:
const app = document.getElementById("app")
const li = document.createElement('li')
myAjax('./test.json',{name:"zhangsan"},2000).then((data)=>{
li.innerHTML = data
app.appendChild(li)
}).catch((reason)=>{
alert(reason)
})
页面上返回:
故意输错URL的情况:
jQuery.ajax
jQuery的ajax库比较古老,没有用promise的形式,因此已经逐渐被axios、fetch等更新的库取代。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const app = document.getElementById("app")
const li = document.createElement('li')
//jQuery入口函数
$(function () {
//请求参数
var list = {};
//调用ajax方法
$.ajax({
//请求方式
type: "GET",
//请求的媒体类型
contentType: "application/json;charset=UTF-8",
//请求地址
url: "./test.json",
//要输入的参数:
data: JSON.stringify(list),
//请求成功的回调函数
success: function (result) {
li.innerHTML = JSON.stringify(result)
app.appendChild(li)
},
error: function(e){
alert(e.status)
}
})
})
</script>
axios
axios官方文档:http://axios-js.com/docs/
axios是一个基于promise的http供客户端使用的库,可以用在浏览器环境和node环境中。
用封装好的axios写起来非常简洁:
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app"></div>
<script>
const app = document.getElementById("app")
const li = document.createElement('li')
// Make a request for a user with a given ID
axios.get('./test.json', {
params: {
user:"zhangsan"
}
})
.then(function (response) {
// handle success
li.innerHTML = JSON.stringify(response.data)
app.appendChild(li)
})
.catch(function (error) {
// handle error
alert(error.response.status)
})
.then(function () {
// always executed
alert('axios请求结束')
});
</script>
</body>