1.ajax
关键词
-
线程 (线程和进程的最小单位 JavaScript是单线程的语言(单线程解析 渲染线程也是单线程))
-
进程 (正在运行的程序)
-
同步(一个线程执行 (同步阻塞))
上一个没有做完 下一个不能执行
-
异步 (多个线程)
上一个和这一个没有关系
概述
AJAX (asynchronous JavaScript and xml) 异步的JavaScript和xml。他是用于发送http请求的,他可以发送异步请求。他可以完成页面的局部刷新功能(在整个页面不刷新的前提下 发送对应的请求改变对应的部分的dom),他的核心对象为XMLHttpRequest(xhr)。
请求流程
ajax的代码实现
//新建请求对象
var xhr = new XMLHttpRequest()
//以对应的请求方式来打开对应的请求地址
xhr.open('get', 'http://jsonplaceholder.typicode.com/todos')
//发送请求
xhr.send()
//监听请求状态的变化 readystate (1-5 1准备发送 2 发送完成 3 发送完成数据准备接收 4数据接收完毕 5 错误)
xhr.onreadystatechange = () => {
//进行判断对应的状态 4是数据接收完毕
if (xhr.readyState == 4) {
//responseText 表示返回的文本(字符串)
console.log(xhr.responseText)
}
}
2.XMLHttpRequest对象的相关属性及方法
属性
-
readyState 状态码
-
status http状态码
-
timeout 超时时间
-
responseText 响应文本
方法
-
open 打开一个请求
-
send 发送请求
-
setRequestHeader 设置请求头
-
getResponseHeader 获取响应头
事件
-
onreadystatechange 监听状态的改变
var xhr = new XMLHttpRequest()
//属性
//readyState 对应的xhr对象的一个状态码(这个状态码只有xhr才有)
// 0 没有请求 1准备发送 2请求已经发送 3请求发送完毕 准备接收响应数据 4响应接收完毕
console.log(xhr.readyState);
//status http状态码 (只要发送http请求都会有)
// 取值为100 - 599
// 1开头(表示成功 但是需要后续操作)
// 2开头 (成功 200)
// 3开头 (重定向 304)
// 4开头 (表示客户端错误 404(找不到页面) 403(权限不足))
// 5开头 (表示服务器错误 500)
console.log(xhr.status);
//responseText 响应的文本
console.log(xhr.responseText);
//responseXML 响应的xml
console.log(xhr.responseXML);
//响应类型
console.log(xhr.responseType);
//响应的地址
console.log(xhr.responseURL);
//设置请求的超时时间
console.log(xhr.timeout );
//方法
//设置请求 open 请求方式 请求地址
xhr.open('get','')
//发送方法 里面的传递的参数是设置给请求体的内容
xhr.send('')
//请求头相关 设置请求头 通过键值对的方式 键 值 都是字符串
xhr.setRequestHeader('Connection','keep-alive')
//响应头获取 通过key来获取value
xhr.getResponseHeader('Content-type')
//事件 当前状态改变的事件
xhr.onreadystatechange = ()=>{
//判断readyState为4 http状态码以2开头
if(xhr.readyState == 4 && /^2\d{2}$/.test(xhr.status)){
//接收数据进行处理
}
}
3.数据渲染案例
<button>请求数据</button>
<ul>
</ul>
<script>
//获取ul
var ul = document.querySelector('ul')
// http://jsonplaceholder.typicode.com/todos?_limit=10&_page=2
//get请求的传参使用?和&做拼接 search传参(query传参)
//第一个前面要添加? 对应的多个参数使用&连接
//get传参时使用地址的拼接来传递参数
// _limit表示 个数 _page表示页数
document.querySelector('button').onclick = function(){
//请求数据
var xhr = new XMLHttpRequest()
//设置请求地址
xhr.open('get','http://jsonplaceholder.typicode.com/todos')
//发送请求
xhr.send()
//接收响应数据
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4 && /^2\d{2}$/.test(xhr.status)){
//接收数据
var str = xhr.responseText
//将字符串转为对应的对象
var result = JSON.parse(str)
//渲染
//遍历result进行渲染
result.forEach(item => {
ul.innerHTML += ` <li>
id: ${item.id}
${item.title}
${item.completed?'💘':'💔'}
</li>`
});
}
}
}
</script>
4.get请求封装
//封装一个对应的get请求的方法
//请求地址 参数 (以对象传递) 对应的处理不一样
export function get(url,params={},callback){
//判断url地址是否传递 如果没有传递直接报错
if(!url){
throw new Error('地址必须传递')
}
//新建请求对象
let xhr = new XMLHttpRequest()
//设置请求地址 (拼接参数到url)
//遍历对象中所有的属性
for(let key in params){
// {_limit:10,_page:1}
// http://jsonplaceholder.typicode.com/todos?_limit=10&_page=1
//判断url里面是否存在? 如果没有就加上
if(!url.includes('?')){
url+=`?${key}=${params[key]}`
}else{
url+=`&${key}=${params[key]}`
}
}
xhr.open('get',url)
//发送请求
xhr.send()
//监听请求状态改变
xhr.onreadystatechange = ()=>{
//判断是否成功
if(xhr.readyState == 4 && /^2\d{2}$/.test(xhr.status)){
//成功调用回调函数传递参数出去
//先转为对象再传递出去
callback(JSON.parse(xhr.responseText))
}
}
}
5.分页渲染示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<button>5</button>
<ul>
</ul>
<script type="module">
import {get} from './ajax.js'
//获取ul
var ul = document.querySelector('ul')
//获取所有按钮
var btns = document.querySelectorAll('button')
//遍历按钮添加事件
Array.from(btns).forEach((v,i)=>{
v.onclick = ()=>{
get('http://jsonplaceholder.typicode.com/todos',{
_limit:10,
_page:i+1
},(res)=>{
ul.innerHTML = ''
res.forEach(item => {
ul.innerHTML += ` <li>
id: ${item.id}
${item.title}
${item.completed?'💘':'💔'}
</li>`
});
})
}
})
</script>
</body>
</html>
6.简单的post请求
<!-- action 提交的地址 method 提交的方式 -->
<form action="https://jsonplaceholder.typicode.com/posts" method="post">
<!-- 如果使用action进行提交 那么提交的内容在对应的输入框中 提交的时候以key value提交
name属性表示的是key 对应的value是输入框的值
<input type="text" name="uname">
<input type="password" name="upwd">
<button type="submit">登录</button>
</form>
<!-- 通过form发送的post请求 需要指定请求方式 这个请求的数据以表单形式发送的
没有指定请求方式 默认以get方式提交
数据暴露在地址栏 他是通过?和&进行拼接 (对应的get请求提交的数据通过字符串的形式)
get请求提交的数据有限 (2kb)
get请求因为在地址栏 所以他会有历史记录
get请求是不安全
只有指定为post才会以post请求提交
post请求 数据是会封装成表单对象存储在对应的请求体中进行提交
数据提交的容量 要远远大于get请求的
而post请求没有历史记录
post安全性要高于get请求
-->
<!-- 异步的post请求 -->
<script>
//获取form表单
document.forms[0].onsubmit = ()=>{
//获取input框的数据
var inputs = document.querySelectorAll('input')
var username = inputs[0].value
var password = inputs[1].value
//新建请求对象
var xhr = new XMLHttpRequest()
//打开连接
xhr.open('post','https://jsonplaceholder.typicode.com/posts')
//设置请求头 告诉后台的我的内容为表单形式
//内容的类型为表单形式
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
//发送数据 key=value&key=value send里面的数据放入在请求体
xhr.send(`username=${username}&password=${password}`)
//监听状态改变
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4 && /^2\d{2}$/.test(xhr.status)){
console.log(xhr.responseText);
}
}
//禁止默认行为
return false
}
</script>
post请求封装
//封装post请求
export function post(url,params={},callback){
//判断url地址是否传递 如果没有传递直接报错
if(!url){
throw new Error('地址必须传递')
}
//新建请求对象
let xhr = new XMLHttpRequest()
//设置请求地址 (拼接参数到url)
xhr.open('post',url)
//设置请求头
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded')
//数据拼接发送
let paramsStr = ""
for(let key in params){
// {_limit:10,_page:1}
// _limit=10&_page=1
paramsStr += `&${key}=${params[key]}`
}
//删除最前面的&
paramsStr = paramsStr.substring(1)
//发送请求
xhr.send(paramsStr)
//监听请求状态改变
xhr.onreadystatechange = ()=>{
//判断是否成功
if(xhr.readyState == 4 && /^2\d{2}$/.test(xhr.status)){
//成功调用回调函数传递参数出去
//先转为对象再传递出去
callback(JSON.parse(xhr.responseText))
}
}
}
7.ajax封装
//将post请求和get请求抽取
export const ajax = (url,option,callback)=>{
//判断是否具备url
if(!url){
throw new Error('地址必须传递')
}
//你传什么就改什么 不传为默认值
let defaultOption = {
method:'get',
data:{},
contentType:'application/json',
timeout:'3000'
}
//遍历对象里面key
for(let key in option){
//默认的选项里面存在这个key
if(defaultOption[key]){
//用option里面对应key的值来替换默认值
defaultOption[key] = option[key]
}
}
//新建请求对象
let xhr = new XMLHttpRequest()
//判断是get请求还是post请求
if(defaultOption.method == 'get'){
//设置请求地址 (拼接参数到url)
//遍历对象中所有的属性
for(let key in defaultOption.data){
// {_limit:10,_page:1}
// http://jsonplaceholder.typicode.com/todos?_limit=10&_page=1
//判断url里面是否存在? 如果没有就加上
if(!url.includes('?')){
url+=`?${key}=${defaultOption.data[key]}`
}else{
url+=`&${key}=${defaultOption.data[key]}`
}
}
}
xhr.open(defaultOption.method,url)
//设置请求头
xhr.setRequestHeader('content-type',defaultOption.contentType)
//判断是否为post请求
if(defaultOption.method == 'post'){
//数据拼接发送
let paramsStr = ""
for(let key in defaultOption.data){
// {_limit:10,_page:1}
// _limit=10&_page=1
paramsStr += `&${key}=${defaultOption.data[key]}`
}
//删除最前面的&
paramsStr = paramsStr.substring(1)
//发送请求
xhr.send(paramsStr)
}else{
//发送请求
xhr.send()
}
//监听请求状态改变
xhr.onreadystatechange = ()=>{
//判断是否成功
if(xhr.readyState == 4 && /^2\d{2}$/.test(xhr.status)){
//成功调用回调函数传递参数出去
//先转为对象再传递出去
callback(JSON.parse(xhr.responseText))
}
}
}
8.ajax promise封装
//将post请求和get请求抽取
export const ajax = (url,option)=>{
//判断是否具备url
if(!url){
throw new Error('地址必须传递')
}
//你传什么就改什么 不传为默认值
let defaultOption = {
method:'get',
data:{},
contentType:'application/json',
timeout:'3000'
}
//遍历对象里面key
for(let key in option){
//默认的选项里面存在这个key
if(defaultOption[key]){
//用option里面对应key的值来替换默认值
defaultOption[key] = option[key]
}
}
//新建请求对象
let xhr = new XMLHttpRequest()
//判断是get请求还是post请求
if(defaultOption.method == 'get'){
//设置请求地址 (拼接参数到url)
//遍历对象中所有的属性
for(let key in defaultOption.data){
// {_limit:10,_page:1}
// http://jsonplaceholder.typicode.com/todos?_limit=10&_page=1
//判断url里面是否存在? 如果没有就加上
if(!url.includes('?')){
url+=`?${key}=${defaultOption.data[key]}`
}else{
url+=`&${key}=${defaultOption.data[key]}`
}
}
}
xhr.open(defaultOption.method,url)
//设置请求头
xhr.setRequestHeader('content-type',defaultOption.contentType)
//判断是否为post请求
if(defaultOption.method == 'post'){
//数据拼接发送
let paramsStr = ""
for(let key in defaultOption.data){
// {_limit:10,_page:1}
// _limit=10&_page=1
paramsStr += `&${key}=${defaultOption.data[key]}`
}
//删除最前面的&
paramsStr = paramsStr.substring(1)
//发送请求
xhr.send(paramsStr)
}else{
//发送请求
xhr.send()
}
return new Promise((resolve,reject)=>{
//监听请求状态改变
xhr.onreadystatechange = ()=>{
//判断是否成功
if(xhr.readyState == 4){
//成功调用resolve传递数据
//先转为对象再传递出去
if(/^2\d{2}$/.test(xhr.status)){
resolve(JSON.parse(xhr.responseText))
}
if(/^4\d{2}/.test(xhr.status)){
reject()
}
}
}
//如果xhr对象有错也调用reject
xhr.onerror = ()=>{
reject()
}
})
}