Ajax
| 优势 | |
|---|---|
| 不需要插件的支持,原生js就可以用 | |
| 用户体验好,不需要刷新页面就可以更新数据 | |
| 减轻服务端和带宽的负担 |
| 缺点 | |
|---|---|
| 搜索引擎的支持度不够 | |
| 因为数据都不在页面上,搜索引擎搜不到 |
Ajax的使用
在js中有内置的构造函数来创建Ajax对象
创建Ajax对象以后,我们就使用Ajax对象的方法发送请求和接受响应
onreadystatechange
//1.创建一个对象XHR new XMLHttpRequesT()
var xhr=new XMLHttpRequest()
console.log(xhr)
//2.配置 open(请求方式,请求地址,是否异步),录入我们的手机号
xhr.open("GET","http://127.0.0.1:5500/01.js/1.txt")
//3.send 发送出去,播出去
xhr.send()
//4.接受数据,注册一个事件,等结果
//btn.onclick=function(){},不过这个需要自己点
//下面这个不用
xhr.onreadystatechange=function(){
//console.log(xhr.readyState)
//http的状态码在200~299都是成功的
if(xhr.readyState===4 && xhr.status===200){
console.log("数据解析完成",xhr.responseText)
}else if(xhr.readyState===4 && xhr.status===404){
console.error("没有找到这个页面")
//location.href=""
}
}
onload
在第四步接受数据的时候,除了onreadystatechange方法之外,还有一个onload方法(它在4的时候才会进来)
xhr.onload=function(){
console.log(xhr.readyState)
if(xhr.status===200){
console.log(JSON.parse(xhr.responseText))
}else if(xhr.status===404){
console.error("没有找到这个页面")
}
}
tip:字符串到对象,需要转一下
JSON.parse()
Ajax同步异步(第三个参数)
true表示异步请求
false表示同步请求
(同步时逐步执行,而异步是可以同时多个执行)
function会后执行
请求方式
1.get post put delete
get 偏向于获取数据
post 偏向于提交数据
put偏向于更新(全部)
delete 偏向于删除信息
patch偏向于部分修改,更新
header options connect(不常用)
实战
npm install json-server -g
json-server -v
json-server 文件(按tap键补全) --watch
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="myget">get</button>
<button id="mypost">post</button>
<button id="myput">put</button>
<button id="mypatch">patch</button>
<button id="mydelete">delete</button>
<script>
//get
//绑事件
myget.onclick = function () {
var xhr = new XMLHttpRequest()
xhr.open("GET", "http://localhost:3000/user")
// 如果get需要传参,就这样写(?关键字,然后后面写你的参数)
//xhr.open("GET", "http://localhost:3000/user?username=ximen")
//回调
xhr.onload = function () {
if (xhr.status === 200) {
console.log(JSON.parse(xhr.responseText))
} else if (xhr.status === 404) {
console.error("没有找到这个页面")
}
}
//发送
xhr.send()
}
//post
mypost.onclick = function () {
var xhr = new XMLHttpRequest()
xhr.open("POST", "http://localhost:3000/user")
//回调
xhr.onload = function () {
if (/^2\d{2|$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
} else if (xhr.status === 404) {
console.error("没有找到这个页面")
}
}
/*1.
post的方法需要你把需要提交的信息放到send中
↓这个表示,传的信息是这种的(带来的格式):name=kerwin&age=100字符串
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
xhr.send(`username=gangdaner&password=123`)*/
//2.
//↓这个表示,传的信息是这种的(带来的格式):{"name":"kerwin"}
xhr.setRequestHeader("Content-Type", "application/json")
xhr.send(JSON.stringify({
username: "ximen",
password: "789"
}))
}
//put(全部修改)
myput.onclick = function () {
var xhr = new XMLHttpRequest()
//传id
xhr.open("PUT", "http://localhost:3000/user/1")
xhr.onload = function () {
if (/^2\d{2|$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
} else if (xhr.status === 404) {
console.error("没有找到这个页面")
}
}
xhr.setRequestHeader("Content-Type", "application/json")
xhr.send(JSON.stringify({
username: "ximen1111111"
}))
}
//patch(部分修改)
mypatch.onclick = function () {
var xhr = new XMLHttpRequest()
xhr.open("PATCH", "http://localhost:3000/user/2")
xhr.onload = function () {
if (/^2\d{2|$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
} else if (xhr.status === 404) {
console.error("没有找到这个页面")
}
}
xhr.setRequestHeader("Content-Type", "application/json")
xhr.send(JSON.stringify({
username: "ximen1111111"
}))
}
//delete
mydelete.onclick = function () {
var xhr = new XMLHttpRequest()
xhr.open("DELETE", "http://localhost:3000/user/2")
xhr.onload = function () {
if (/^2\d{2|$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
} else if (xhr.status === 404) {
console.error("没有找到这个页面")
}
}
xhr.send()
}
</script>
</body>
</html>
json上:
封装Ajax
//封装
ajax({
url:"http://localhost:3000/user",//地址
method:"GET",//请求方式
async:true,//异步
data:{
username:"kerwin",
password:"123"
},//data传入的数据
headers:{},
//回调函数
success:function(res){
console.log(res)
},
error:function(err){
console.log(err)
}
})
读代码(js:1111~5555)
get
.111111.
(这些在js文件中)
写了上面那个之后,在html中需要引入一下
然后在html中传参并调用:
.444444.
js中:
//发送请求——————————————————
const xhr =new XMLHttpRequest()
xhr.open(method,url,async)
xhr.onload=function(){
console.log(xhr.readyState)
if (!/^2\d{2}$/.test(xhr.status)) {
error('错误状态码:${xhr.status}')
//!!!!回调↑,对应上面封装里的error
return
}
//执行解析——————————————————
//try catch即使解析错误,也不报红错(把返回来的值用json-parse来解析)
try{
let result=JSON.parse(xhr.responseText)
//解析完后再用success回调
success(result)
}catch(err){
error(`解析失败!因为后端返回的结果不是json格式字符串`)
}
}
上面在json中对success,error传了实参;所以这时候:要在html传形参res,err
最后js中发送一下:
xhr.send()
post
如果是post的请求方式的话:
要写headers,headers与POST有关,里面传"Content-Type","application/x-www-form-urlencoded"这个或者另一个
.555555.
然后最后这样写
//设置请求头内的信息
for(let k in headers)xhr.setRequestHeader(k,headers[k])
xhr.send(data)
tip...js中 这是一个小函数,用于如果你的data中想传一个对象,把一个对象转换为key=value&key=value的形式
function queryStringify(obj){
let str=``
for(let k in obj)str +=`${k}=${obj[k]}&`
return str.slice(0,-1)
}
如果是需要转的话,js中需要再补一个代码
data=queryStringify(data)
.222222.
判断一下你的data是对象吗
所以,综上,如果想把data对象形式转为post里面的两种形式的话,就可以写这段代码(直接一举两得)
if(typeof data ===`object`&& headers["Content-type"]?.indexOf
("json")>-1){
data=JSON.stringify(data)
}else{
data=queryStringify(data)
}
你这个send(data)有局限性,这样的话你的post能用,但是get又用不了了,所以你可以这样写个小判断在js中
if(/^get$/i.test(method)){
xhr.send()
}else{
xhr.send(data)
}
.333333.
如果是get请求,并且有参数,那么直接组装一下url信息
if(/^get$/i/test(method)&&data)url += '?'+data
回调地狱(嵌套金字塔)
test.json
{
"news":[
{"id":1,"title":"男人看了沉默,女人看了流泪","author":"kerwin"}
,
{"id":2,"title":"震惊!他年薪仅有1元","author":"tiechui"}
],
"comments":[
{"id":1,"body":"我是男人","newsId":1},
{"id":2,"body":"我是女人","newsId":1},
{"id":3,"body":"我年薪2元","newsId":2},
{"id":4,"body":"我年薪3元","newsId":2}
]
}
html中
<script src="util.js"></script>
<script>
//Ajax嵌套,也就是回调地狱(也就是回调函数嵌套过多导致)
//tiechui已经登录
ajax({
url: "http://localhost:3000/news",
method: "GET",
data: {
author: "tiechui"
},
success: function (res) {
console.log(res[0])
//拿tiechui的id对应的评论
ajax({
url: "http://localhost:3000/comments",
data: {
newsId: res[0].id
},
success: function (res) {
console.log(res)
}
})
}
})
</script>
在JS中,当我们使用AJAX进行异步操作时,经常会遇到需要多个操作按顺序执行的情况(比如你找一篇文章,就会有对应的很多评论,这些评论又会有一些对应的别的.....)
所以如果我们使用传统的回调函数来处理这种情况,代码会变得非常复杂,这就是所谓的“回调地狱”(也就是回调函数嵌套过多导致)。
Promise
(是一种ES6的语法,并且是一个专门用来解决异步回调地狱问题)
111.基础语法
Promise主要有三种状态:
pending(正在执行中)→fulfilled(成功)/reject(失败)
//Promise构造函数
//resolve,reject这两的参数,分别对应下面的then和catch函数
var q = new Promise(function(resolve,reject){
//这里放异步代码
//resolve("win")
//reject("error")
})
//q就是promise对象
q.then(function(res){
//兑现承诺,则then执行
console.log("success",res)
}).catch(function(err){
//拒绝承诺,catch被执行
console.log("fail",err)
})
222.Promise封装Ajax(.then.then链式用法)
js中
function pajax(options) {
return new Promise((resolve, reject) => {
ajax({
...options,//展开
success(res) {
resolve(res)
},
error(err) {
reject(err)
}
})
})
//return q
}
/*pajax().then(function(){
}).catch(err=>{
})*/
async和await语法
(是一个ES7的语法,这个语法是回调地狱的终极解决方案)
async(异步)await(等待):更加优雅的异步编程的写法
await
-
也就是,它必须等await后面这个句子执行了,它才会继续往下执行
-
不过这个只针对于async内部的异步成同步,外部该怎么还怎么
-
await后可以跟同步代码,但是没有意义,也就是写不写wait都是一个效果
-
除了同步代码,await后只能放promise对象
<script type="module">
import{pajax} from`./util.js`
async function test(){
//这个意思也就是,它必须等await后面这个句子执行了,它才会继续往下执行
//不过这个只针对于async内部的异步成同步,外部该怎么还怎么
//await后可以跟同步代码,但是没有意义,也就是写不写wait都是一个效果
//除了同步代码,await后只能放promise对象
var res = await pajax({
url:"http://localhost:3000/news",
data:{
author:"kerwin"
}
})
//console.log(res)
//再往下连着写就会构成链式
var res1=await pajax({
url:"http://localhost:3000/comments",
data:{
newsId:res[0].id
}
})
return res1
}
test() .then(res=>{
console.log("返回结果",res)
}).catch(err=>{
console.log(err)
})
console.log(33333)
</script>
问: 上面代码的catch捕获在async外,那如果现在就是要求你在async内实现,该怎么写呢?
答:用try-catch包住
<script type="module">
import{pajax} from`./util.js`
async function test(){
try{
var res = await pajax({
url:"http://localhost:3000/news",
data:{
author:"kerwin"
}
})
//console.log(res)
//再往下连着写就会构成链式
var res1=await pajax({
url:"http://localhost:3000/comments",
data:{
newsId:res[0].id
}
})
console.log("success",res1)
}catch(err){
console.log("err",err)
}
}
test()
</script>
fetch
-
fetch兼容性不好
-
是为了取代XMLHttpRequest,而不是为了取代Ajax
-
fetch不能直接使用catch,所以我们的应对方案是用一个if判断,并在else中使用拒绝承诺,然后catch才有用
get
//默认是get请求
//fetch传参是拼到地址上的方式
var username="kerwin"
fetch('http://localhost:3000/user?username=${username}')
.then(res=>{
console.log(res)
if(res.ok){
//拿数据,res.json返回的是一个promise对象
return res.json()
}else{
//拒绝承诺
return Promise.reject({
//...准确告诉你哪里错了
})
}
})
.then(res=>{
console.log("success",res)
}).catch(err=>{
console.log("error",err)
})
其他同理,换汤不换药
cookie(本地存储)
-
本地存储功能(比如记住用户名,我们在之前用的是localStorage)
-
cookie是浏览器关了就没有了,而localStorage可以“永久”存储
如何代替localStorage实现增删改查?
- 增(存)
<body>
<button id="savebtn">存(增)</button>
<script>
savebtn.onclick=function(){
//只能一条一条存
//document.cookie="username=kerwin;path=/文件名" key=value的格式;path路径(为了安全)
document.cookie="age=18"
//过期时间设置(到时间,这条数据就没了)
var date=new Date()
date.setMinutes(date.getMinutes()+1)
document.cookie='username=kerwin;expires=${date.toUTCString()}'
}
</script>
</body>
- 查(获取)
- 修(同名覆盖)
- 删
给删除键设置过期时间(也就是设置让它比当前时间还要少,就可以达到一点删除,就可以删了的效果)
cookie的特点
只能存文本,存不了对象
jsonp
是json的一种“使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据
同源策略:
虽然同源策略在一定程度上提高了网站的安全,但也会给程序员带来一些麻烦,例如在访问一些开发接口时,由于同源策略的存在,会调用失败。要解决这种问题就需要用到跨域,跨域的方法有许多种,其中最经典的就是 JSONP。
解决: