来手撸一个简化版Ajax

120 阅读3分钟

我正在参加「掘金·启航计划」

前言

在我们手撸ajax之前,我们先来Ajax吧!

Ajax是什么

在我们写前端代码时,我们是不是都苦恼着如何做前后端互通呢?而今天的主角就是帮我们完成这件事的。所以Ajax的作用就是用于浏览器与服务器之间使用异步数据传输(HTTP 请求),做到局部请求以实现局部刷新。让我们可以请求到服务端的数据用于渲染浏览器端。

Ajax的作用

  1. 不刷新页面而更新网页(局部刷新
  2. 在页面加载后从服务器请求数据
  3. 在页面加载后从服务器接受数据
  4. 在后端向服务器发送数据

原生JS向后端请求方式

//原生js提供的接口请求方法
let xhr = new XMLHttpRequest()
xhr.open(method, url, async, [user-name], [user-pass])
xhr.onreadystatechange  = function() {     //监听
    if(xhr.readyState === 4 && xhr.status === 200) {
        console.log(xhr.responseText);
    }
}
xhr.send([请求主题])

原生JS提供了一个 XMLHttpRequest 方法。我们直接new 一个xhr实例对象。然后我们直接调用XMLHttpRequest上的open方法。同时在open方法中携带method、url、async(async=false为同步执行)、[user-name]、[user-pass](可选、url的认证资格)。

http 请求方式(method)

  • GET: 从服务器获取数据(向服务器推送数据)
  • POST: 向服务器推送数据(从服务器获取数据)
  • DELETE:删除服务器的某些内容
  • PUT: 向服务器存放一些内容  
  • HEAD:  只想获取服务器返回的响应头信息,不要响应体
  • OPTIONS: 一般使用它向服务器发送一个探测请求,如果返回的信息,说明客户端和服务器建立了连接,可以继续请求
  • TRACE:  基于cross - domain 进行跨域请求的时候

之后我们继续可以调用XMLHttpRequestonreadystatechange方法用来监听的状态。根据状态码来判断请求是否成功和返回数据。

readyState的状态

  • 0: 刚刚创建xhr
  • 1:执行了open这个操作
  • 2:请求已经发送,响应头已经被客户端接受
  • 3: 响应主题正在返回     // 还没被接收
  • 4:响应主体已经被客户端接收

http状态码

  • 1xx: 请求已经接受,正在处理
  • 2xx:成功。请求被成功接受
  • 3xx:成功,资源已经重定向了  // 换了个url
  • 4xx:客户端错误
  • 5xx: 服务端错误

最后我们调用XMLHttpRequestsend方法根据情况向后端传递参数。这样我们既完成了原生的JS请求方式。

我们来一个实例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!--  原生的请求方式 -->
    <script>
        let xhr = new XMLHttpRequest()
        xhr.open('GET', 'https://www.fastmock.site/mock/39ac87de3060aa2bb2ba20a0ff375c81/cat-movie/mostLike')
        xhr.onreadystatechange = function () {     //监听
            if (xhr.readyState === 4 && xhr.status === 200) {
                console.log(JSON.parse(xhr.responseText));
            }
        }
        xhr.send()
    </script>
</body>
</html>

屏幕截图(86).png

直接使用封装好的Ajax方法

我们先来看一看封装好的Ajax方法的使用方式,我们同样是可以向后端请求到数据,而且会你原生JS的请求方式更加的便捷。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
    <title>Document</title>
</head>
<body>
    <<script>
        $.ajax({
            url:'https://www.fastmock.site/mock/39ac87de3060aa2bb2ba20a0ff375c81/cat-movie/mostLike',
            method: 'GET',
            dataType:'json',
            data:null,
            async: true,
            cache: true,
            success: res => {
                console.log(res);
            }
         })
    </script> 
</body>
</html>

屏幕截图(87).png

手撸一个简化版Ajax

在看完直接封装的Ajax方法,那我们是否好奇它是怎么实现的呢?那接下来我们就来自己封装一个简化版的Ajax来看看他的实现原理吧。

HTML代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="ajax.js"></script>
    <title>Document</title>
</head>
<body>
    <script>
        ajax({
            url: 'https://www.fastmock.site/mock/39ac87de3060aa2bb2ba20a0ff375c81/cat-movie/mostLike',
            method: 'GET',
            dataType: 'json',
            data: {
                name: 'abc',
                age: 10
            },
            async: true,
            cache: true,
            success: res => {
               console.log(res);
            }
        })
    </script> 
</body>
</html>
JS代码部分:
function  ajax(options) {
    let {  // 结构前端参数
        url,
         method= 'GET',
          data= null,
          dataType= 'JSON',
          async = true,
          cache = true,
          success,
          error
        } = options
    let xhr = new XMLHttpRequest() 
    // 处理参数
    if(method.toUpperCase() === 'GET') { // 处理不同的请求方式
        if(data) {
            url += '?'
            for(let key in data) {
                url += `${key}=${data[key]}&`
            }
            xhr.open(method, url, async)
            xhr.send()
        }
    }else {  //post
        xhr.open(method, url, async)
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') // 请求头
        xhr.send(data)
    }
    xhr.onreadystatechange = () =>{ // 监听请求是否成功,并返回数据
        if(xhr.readyState === 4){
            if( !/^(2|3)\d{2}$/.test(xhr.status)) {
                error && error(xhr.statusText, xhr)
            }
           let result =  handleDataType(xhr)  //格式化处理
           success && success(result, xhr)
        }
    }
    function handleDataType(xhr) { //拿到前端需要的数据格式,进行格式化处理
       dataType = dataType.toUpperCase()
       let  result = xhr.responseText
        switch(dataType) {
            case 'TEXT':
                break;
            case 'JSON':
                result = JSON.parse(result)
                break;
            case 'XML':
                result = xhr.responseXML
                break;
            default:
        }
        return result
    }
}

在通过简单的封装,我们自己的封装的Ajax也能实现JQ里封装好的ajax的部分功能。

屏幕截图(88).png

总结

话已至此,便落下帷幕。学习阶段,欢迎各位大神补充观点。