XMLHttpRequest,FormData对象和Promise封装

    科技2024-10-29  12

    之前在项目中看到过一段上传文件的代码,其中有这样一句:

    const form = new FormData();

    当时不知道这个FormData()是个什么东西,好像也没有这样的构造函数,但是用的时候都是复制粘贴的,代码也能正常运行,所以也就没有多想。

    今天无意中查了一下XMLHttpRequest,原来这玩意还有Level 1标准和Level 2标准,我知道的那些都是Level 1,而FormData是Level 2里面的新增特性,下面就来系统总结一下。

    什么是 XMLHttpRequest 对象

    以下内容引用自W3School:

    XMLHttpRequest 对象用于在后台与服务器交换数据。

    在不重新加载页面的情况下更新网页在页面已加载后从服务器请求数据在页面已加载后从服务器接收数据在后台向服务器发送数据

    如何创建 XMLHttpRequest 对象

    这里回顾一下Level 1的用法。

    首先,新建一个XMLHttpRequest的实例。

    var xhr= new XMLHttpRequest();

    然后,向远程主机发出一个HTTP请求。这里的第三个参数Async规定请求是否异步处理,true或者不传都表示脚本会在 send() 方法之后继续执行,而不等待来自服务器的响应。也就是说,send()这句是异步的。

    xhr.open("GET", "https://www.xiaomizhou.com", true); xhr.send();

    接着,就等待远程主机做出回应。这时需要监控XMLHttpRequest对象的状态变化,指定回调函数。

    xhr.onreadystatechange = function () { if (request.readyState === 4 && request.status === 200) { console.log(request.responseText) } }

    XMLHttpRequest对象的主要属性

    xhr.readyState:XMLHttpRequest对象的状态,一共有5种状态 0 - (未初始化)还没有调用send()方法 1 - (载入)已调用send()方法,正在发送请求 2 - (载入完成)send()方法执行完成,已经接收到全部响应内容 3 - (交互)正在解析响应内容 4 - (完成)响应内容解析完成,可以在客户端调用了

    xhr.status:服务器返回的状态码,等同于HTTP的状态 200:请求成功 400: 内部服务器错误

    xhr.responseText:服务器返回的文本数据

    xhr.responseXML:服务器返回的XML格式的数据

    xhr.statusText:服务器返回的状态文本

    request.onload = function(e){} 请求成功

    request.process = function(e){} 请求正在加载

    request.onerror = function(e){} 请求失败

    老版本的缺点

    老版本的XMLHttpRequest对象有以下几个缺点:

    1. 只支持文本数据的传送,无法用来读取和上传二进制文件。 2. 传送和接收数据时,没有进度信息,只能提示有没有完成。 3. 受到"同域限制"(Same Origin Policy),只能向同一域名的服务器请求数据。

    新版本的功能

    新版本的XMLHttpRequest对象,针对老版本的缺点,做出了大幅改进。

    1. 设置HTTP请求的时限

    新版本的XMLHttpRequest对象,增加了timeout属性。下面的语句,将最长等待时间设为3000毫秒。过了这个时限,就自动停止HTTP请求。

    xhr.timeout = 3000;

    与之配套的还有一个timeout事件,用来指定回调函数。

    xhr.ontimeout = function(event){ alert('请求超时!'); }

    2. FormData对象

    ajax操作往往用来传递表单数据。为了方便表单处理,HTML 5新增了一个FormData对象,可以模拟表单。

    首先,新建一个FormData对象。

    var formData = new FormData();

    然后,为它添加表单项。

    formData.append('username', '张三'); formData.append('id', 123456);

    最后,直接传送这个FormData对象。这与提交网页表单的效果,完全一样。

    xhr.send(formData);

    FormData对象也可以用来获取网页表单的值。

    var form = document.getElementById('myform'); var formData = new FormData(form); formData.append('secret', '123456'); // 添加一个表单项 xhr.open('POST', form.action); xhr.send(formData);

    FormData对象最大的作用是上传文件。假定files是一个"选择文件"的表单元素(input[type=“file”]),我们将它装入FormData对象。

    var formData = new FormData(); for (var i = 0; i < files.length;i++) { formData.append('files[]', files[i]); }

    然后,发送这个FormData对象。

    xhr.send(formData);

    3. 跨域资源共享(CORS)

    新版本的XMLHttpRequest对象,可以向不同域名的服务器发出HTTP请求。

    使用"跨域资源共享"的前提,是浏览器必须支持这个功能,而且服务器端必须同意这种"跨域"。如果能够满足上面的条件,则代码的写法与不跨域的请求完全一样。

    xhr.open('GET', 'http://other.server/and/path/to/script');

    4. 进度信息

    新版本的XMLHttpRequest对象,传送数据的时候,有一个progress事件,用来返回进度信息。

    它分成上传和下载两种情况。下载的progress事件属于XMLHttpRequest对象,上传的progress事件属于XMLHttpRequest.upload对象。

    首先,定义事件的回调函数。

    xhr.onprogress = updateProgress; // 下载事件的回调 xhr.upload.onprogress = updateProgress; // 上传事件的回调

    然后,在回调函数里面。使用这个事件的一些属性。

    function updateProgress(event) { if(event.lengthComputable) { var percentComplete = event.loaded / event.total; } }

    上面的代码中,event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0。

    与progress事件相关的。还有其他5个事件,可以分别指定回调函数。

    load:传输成功完成。 abort:传输被用户取消。 error:传输中出现错误。 loadstart:传输开始。 loadEnd:传输结束,但不知道成功还是失败。

    Promise封装ajax请求

    下面代码中,getJSON是对 XMLHttpRequest 对象的封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回一个Promise对象。

    const getJSON = function(url) { const promise = new Promise(function(resolve, reject){ const handler = function() { if (this.readyState !== 4) { return; } if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; const client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler; client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); }); return promise; }; getJSON("/posts.json").then(function(json) { console.log('Contents: ' + json); }, function(error) { console.error('出错了', error); });

    参考: XMLHttpRequest 详解 XMLHttpRequest Level 2 使用指南 - 阮一峰 Promise对象 - 阮一峰

    Processed: 0.025, SQL: 8