ajax与axios

今天被问到用没用过ajax axios,我回答 经常用axios,但ajax用的比较少,额。。。

首先,axios是ajax的promise封装版,跟jquery是ajax的回调函数封装版类似

ajax (async jasvascript And xml)

[r1] Ajax文档 (MDN) 本文大篇幅参考MDN

[r2] AJAX (阮一峰)

1.1 ajax

1)ajax介绍

ajax (async jasvascript And xml)即异步JavaScript和XML,但

尽管X在Ajax中代表XML, 但由于JSON的许多优势,比如更加轻量以及作为Javascript的一部分,目前JSON的使用比XML更加普遍。JSON和XML都被用于在Ajax模型中打包信息。

ajax有很多种方式:1XHR 2Fetch API 3Server-sent事件(使用服务器发送事件)

fetch 和 server-sent,在IE中都不被支持,我们把重点放在XHR上

2)XMLHttpRequest API是Ajax的核心

首先看看一些常用属性和方法:

名称 作用
onreadystatechange 该属性指定一个响应的回调
readyState 请求状态:0 1 2 3 4请求完毕
4 === xhr.DONE
status 响应状态码
一些方法
open 初始化一个请求
setHeaders myReq.setRequestHeader(header, value); 设置头部信息必须在open和send之间
send 发送请求
一些事件
onerror 错误发生的回调
timeout 超时回调
onload

在来看一个完整例子

let httpRequest;
if (window.XMLHttpRequest) {
    httpRequest = new XMLHttpRequest()
} else {
    console.log('出错了,请升级您的浏览器,目前版本不支持发送HTTP请求!')
}
function makeRequest() {
    // 1 请求逻辑
    httpRequest.onreadystatechange = resHandler
    httpRequest.open('GET', 'http://www.baidu.com', true)
    // 请求方法必须大写,第三参数标识是否异步
    httpRequest.send()
}

function resHandler() {
    // 2 响应数据处理逻辑
    console.log('[]:', httpRequest.readyState)
    if (httpRequest.readyState === XMLHttpRequest.DONE) { // 或者===4
        if (httpRequest.status === 200) {
            console.log('收到服务器响应数据')
            console.log('[返回为字符串]:', httpRequest.responseText)

        } else {
            console.log('出错!', httpRequest.status)
        }
    }
}

makeRequest()
// 启动

ajax用于无刷新请求数据,它的一个经典案例是 文件上传

1.2 文件上传

提交表单和上传文件共有两种方法:

  • 使用ajax,灵活,但复杂
  • FormData API,简单,但无法使用JSON.stringify转化为一个对象字符串(why?),因为xhr.send(new FormData(elForm))无法拿到数据
1)使用ajax提交数据

有两个原因,这种方法摒弃:1代码较为复杂 2兼容性差

但我在阅读的时候,有一个疑惑,在MDN上说:

在使用ajax上传文件的时候,发送二进制内容的最佳途径是通过 ArrayBuffersBlobs 结合 send() 方法甚至 FileReader API 的 readAsArrayBuffer() 方法。但是,自从该脚本的目的变成处理 可字符串化 的原始数据以来,我们使用 sendAsBinary() 方法结合 FileReader API 的 readAsBinaryString() 方法。同样地,上述脚本仅当你处理小文件时行之有效。如果不打算上传二进制内容,就考虑使用 FormData API 来替代。

最后一句,如果处理不打算上传二进制内容就用FormData,就用FormData API代替

这里的二进制内容指的是什么?图片?可执行文件?

这里指的是二进制对象,能够被JSON.parse反序列化的字符串对象

2)使用FormData API提交数据【重点】

这也是目前通用方法

直接上案例,简单

<script>
    function AJAXSubmit (oFormElement) {
        if (!oFormElement.action) { return; }
        var oReq = new XMLHttpRequest();
        oReq.onload = ajaxSuccess();
        if (oFormElement.method.toLowerCase() === "post") {
            oReq.open("post", oFormElement.action);
            oReq.send(new FormData(oFormElement));
            # 核心代码
            # 下面是兼容GET请求,作为扩展内容【了解】
        } else {
            var oField, sFieldType, nFile, sSearch = "";
            for (var nItem = 0; nItem < oFormElement.elements.length; nItem++) {
                oField = oFormElement.elements[nItem];
                if (!oField.hasAttribute("name")) { continue; }
                sFieldType = oField.nodeName.toUpperCase() === "INPUT" ?
                    oField.getAttribute("type").toUpperCase() : "TEXT";
                if (sFieldType === "FILE") {
                    for (nFile = 0; nFile < oField.files.length;
                         sSearch += "&" + escape(oField.name) + "=" + escape(oField.files[nFile++].name));
                } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
                    sSearch += "&" + escape(oField.name) + "=" + escape(oField.value);
                }
            }
            oReq.open("get", oFormElement.action.replace(/(?:\?.*)?$/, sSearch.replace(/^&/, "?")), true);
            oReq.send(null);
        }
    }
</script>

<form action="register.php" method="post" enctype="multipart/form-data"
      onsubmit="AJAXSubmit(this); return false;">
    <fieldset>
        <legend>Upload example</legend>
        <p>
            姓名: <input type="text" name="firstname" /><br />
        </p>
        <p>
            您的照片:
            <input type="file" multiple name="photos[]">
        </p>
        <p>
            <input type="submit" value="Submit" />
        </p>
    </fieldset>
</form>

我们来看看FormData是什么?

1.3 FormData

1)首先,我们看3行代码【注意】

// formData 只接受文件、Blob 或字符串,不能直接传递数组,所以必须循环嵌入
for (let i = 0; i < photos.files.length; i++) {
    formData.append('photo', photos.files[i]);
}

会发现FormData不是一个简单的字典(map),因为字典中重名会被覆盖,FormData是一个对象,猜测内部维护了一个数组。以后可能会新增传入数组的方法。

FormData特别简单,他可以接受的值有文件、Blob 和字符串

var formData = new FormData();
formData.append(key, value, [name]);

[name] 第三个为可选参数,设置发送请求的头 Content-Disposition 指定文件名

2)特殊用例

var formData = new FormData(someFormElement);

直接将一个Form标签解析,但注意只能解析具有name属性的字段

formdata可以输入File,Blob,那么这两个又是什么?

1.4 FileBlob

Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。

File 接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。通常情况下,File对象的来源为input标签输入的 FileList对象数组,File没有啥特殊功能,暂不关注。

首先,我们来看一下Blob如何创建

var aBlob = new Blob( array, options );

创建一个Blob对象试试:

var aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; // 一个包含DOMString的数组
var oMyBlob = new Blob(aFileParts, {type : 'text/html'}); // 得到 blob

刚刚说Blob中可以放ArrayBuffer,来看看它是什么

1.4.1 ArrayBuffer

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。它是一个字节数组,通常在其他语言中称为“byte array”。

最基本的

const buffer = new ArrayBuffer(8);
// 创建8个字节的缓冲区

var view   = new Int32Array(buffer);
// 用一个有符号32位类型化数组来用这个缓冲区

典型案例,从文件中获取buffer

function file2buffer(file){
    return new Promise((re,rj)=>{
        const rd = new FileReader()

        rd.onload = e => re(e.target.result)
        rd.onerror = e => rj(rd.error)
        // 先监听,后读取
        rd.readAsArrayBuffer(file)
    })
}

上面相当于File转buffer,那么buffer转File呢?

首先,来看看File构造函数

var myFile = new File(bits, name[, options]);
  • bits一个包含ArrayBuffer,ArrayBufferView,Blob,或者 DOMString 对象的 Array — 或者任何这些对象的组合。这是 UTF-8 编码的文件内容。
  • name USVString,表示文件名称,或者文件路径。
// 那么转File就很简单
new File([buf], filename);

再看,Blob与Buffer的转换,其实Blob与File类似,所以把所有的File变成Blob就可以了。

new Blob([buf], filename);
posted @ 2021-06-10 11:05  那好好  阅读(368)  评论(0)    收藏  举报