AJAX

173 阅读5分钟

AJAX 简介

Async JavaScript And XML 是AJAX的全称,它的作用是用JS发送请求和接收响应
AJAX是浏览器上的功能,浏览器可以发请求,收响应
浏览器在window上加了一个XMLHttpRequest函数
用这个构造函数(类)可以构造出一个对象
js通过它实现发请求,收响应

调试准备工作

新建一个server.js文件,用node打开作为服务器
代码链接:server.js

终端开启服务命令:   node 文件名    端口号
                    node server.js http://localhost:8080
                    
这种调试方法不方便,所以推荐使用node-dev,安装命令:
                    yarn global add node-dev 或者 npm install -g node-dev
                    开启服务命令:
                    node-dev server.js

html请求

让我们先捋一捋常规请求方式,通常html中插入link标签script等标签后服务器会向服务器请求,服务器通过不同的请求路径传入不同的文件,代码如下:

大图链接

访问
Web的运作原理:一次HTTP请求对应一个页面。 如果要让用户留在当前页面中,同时发出新的HTTP请求,就必须用JavaScript发送这个新请求,接收到数据后,再用JavaScript更新页面,这样一来,用户就感觉自己仍然停留在当前页面,但是数据却可以不断地更新。

AJAX加载步骤

1.创建HttpRequest对象(全称是XMLHttpRequest)
2.调用对象的open方法
3.监听对象的onload & onerror事件(推荐使用onreadystatechange事件)
4.调用对象的send方法(发送请求)

加载CSS

html代码(并未插入link标签)

ajax
服务器文件需要添加一个路由

else if (path === '/style.css') {
        response.statusCode = 200
        response.setHeader('Content-Type', 'text/css;charset=utf-8')
        response.write(fs.readFileSync('public/style.css'))
        response.end()
    }

css文件内容

h1{
    color: blue;
}

main文件监听点击事件,如果触发点击事件加载AJAX

getCSS.onclick = ()=>{
    const request = new XMLHttpRequest();
    request.open('GET','style.css')
    request.onload = ()=>{
        const style = document.createElement('style')
        console.log('可以访问')
        style.innerHTML = request.response
        document.head.appendChild(style)
    }
    request.onerror = ()=>{
        console.log('失败了')
    }
    request.send()
}

点击加载CSS效果
点击后触发点击事件加载CSS成功

加载JS

getJS.onclick = ()=>{
    const request = new XMLHttpRequest();
    request.open('GET','test.js')
    request.onload = ()=>{
        console.log('可以访问')
        const script = document.createElement('script')
        script.innerHTML = request.response
        document.body.appendChild(script)
    }
    request.onerror = ()=>{
        console.log('失败了')
    }
    request.send()
}

加载HTML

getHTML.onclick = ()=>{
    const request = new XMLHttpRequest();
    request.open('GET','new.html')
    request.onload = ()=>{
        
        console.log('可以访问newHTML')
        const div = document.createElement('div')
        div.innerHTML = request.response
        document.body.appendChild(div)
    }
    request.onerror = ()=>{
        console.log('失败了')
    }
    request.send()
}

onreadystatechange事件

简单的来说使用onreadystatechange 可以返回XMLHttpRequest对象每个阶段的状态码

onreadystatechange事件状态码

getCSS.onclick = ()=>{
    const request = new XMLHttpRequest();
    request.open('GET','style.css')
    request.onreadystatechange = ()=>{
        if(request.readyState === 4){
            if((200<= request.status < 300)){
                const style = document.createElement('style')
            style.innerHTML = request.response
            document.head.appendChild(style)
            console.log('加载成功')
            }else{
                console.log('加载失败')
            }
        }
    }
    request.send()
}

加载xml

getXML.onclick =()=>{
    const request = new XMLHttpRequest();
    request.open('GET','4.xml')
    request.onreadystatechange =()=>{
        if(request.readyState === 4){
            if( 200 <= request.status <=300){
                const dom = request.responseXML
                const text = dom.getElementsByTagName('warning')[0].textContent
                console.log(text.trim())
            }
        }
    }
    request.send()
}

总结HTTP是个框,什么都能往里装
可以装HTML,CSS,JS,XML....
记得设置正确的Content-Type,只要你知道怎么解析这些内容你就可以使用这些内容
解析方法
得到CSS之后生成style标签
得到JS之后生成script标签
得到html之后使用innerHTML和DOM API
不同类型的数据有不同类型的解析方法

JSON

全称Javascript Object Notation
JSON是一门b标记语言,和HTML,xml,markdown一样,用来展示数据
JSON官方文档链接

对象示意图

铁轨图
其他图点击官方文档查看

json支持的数据类型

string -只支持双引号,不支持单引号,和无双引号
number -支出科学计数法
bool -true 和false
null -没有underfined
object
array
不支持函数,不支持变量

加载代码效果链接

代码
效果

异步和回调

同步请求
能直接拿到结果,拿不到结果不会进行下一步
异步请求
请求发送后继续执行其他命令,等结果出来后返回

回调

被另一个函数调用的函数是回调

function f1(x){
    console.log(x)
}
function f2(fn){
    fn('你好')
}
f2(f1)

异步和回调的关系

异步任务需要在得到结果时通知JS来拿结果,所以可以让JS留一个函数地址给浏览器
异步任务完成时浏览器调用该地址,同时把结果作为参数传给该函数这个函数是留给浏览器调用的,所以是回调函数
array,forEach(n=>console.log(n))就是同步回调

异步任务有两个结果,成功或失败

方法1.回调接受两个参数

fs.readFile('./1.txt',(error,data)=>{
    if(error){console.log('失败');return}
    console.log(data.toString())//成功
})

方法2.搞两个回调

ajax('get','/1.json',data=>{},error=>{})
//前面函数是成功回调,后面函数是失败回调
ajax('get','/1.json'.{
    success:()=>{},fail:()=>{}
})
//接受一个对象,对象有两个key表示成功和失败

这些方法的不足
1.不规范,名称五花八门
2.很容易出现回调地狱,代码变得看不懂
3.很难进行错误判断

回调地狱
以封装ajax为例讲解promise

ajax = (method,url,options)=>{
    const {success,fail} = options
    const request = new XMLHttpRequst()
    request.open('method',url)
    request.onreadystatechange =()=>{
        if(requst.readyState === 4){
            if(request.status < 400){
                success.call(null,request.response)
            }else if(request.status >= 400){
                fail.call(null,request,request.status)
            }
        }
    }
    request.send()
}
ajax('get','/xxx',{
    success(response){},fail:{request,status}=>{}
})//左边是funciton 缩写,右边是箭头函数

promise写法

//正常调用姿势
ajax('get','/xxx',{
    success(response){},fail:{request,status}=>{}
})//用了两个回调,还有success和fail
//promise调用姿势
ajax('get','/xxx').then((response)=>{},(request)=>{})
//虽然也是回调单不需要记success和fail,then的第一个参数就是success第二个参数就是fail
//下面的ajax返回一个api
ajax = (method,url,options)=>{
    return new Promise((resolve,reject)=>{
        const {success,fail} = options
        const request = new XMLHttpRequst()
        request.open('method',url)
        request.onreadystatechange =()=>{
            if(requst.readyState === 4){
                if(request.status < 400){
                    success.call(null,request.response)
                }else if(request.status >= 400){
                    fail.call(null,request,request.status)
                }
            }
        }
        request.send()
    })
}

这里封装的AJAX只是为了演示Promise的写法,还有很多的缺陷
比如post无法上传数据
request.send(这里可以上传数据)
不能设置请求头
request.setRequestHeader(key,value) 我们可以使用jQuery.ajax()或者使用axios()
相关链接

小结

第一步
return new Promise((resolve,reject)=>{})
任务成功则调用resolve(result)
任务失败则调用reject(error)
resolve和reject会再去调用成功和失败函数
第二步
使用.then(success,fail)传入成功和失败函数