获取网络通信进度实践

网络请求是现代Web开发中不可或缺的一部分,无论是从服务器获取资源,还是提交数据,了解请求的进度对于提升用户体验非常关键。本文将详细介绍如何使用Fetch API和XMLHttpRequest(XHR)来执行网络请求,并重点说明如何获取这两种方法的网络请求进度。此外也将探讨在使用XHR进行文件上传时如何获取上传进度,以及Fetch API的局限性。

Fetch基础

Fetch API提供了一个强大且灵活的接口,用于对网络请求进行操作。它是一个低级别的API,可以控制请求的各个方面。以下为一个基础的Fetch API调用示例,它通过网络获取资源。

javascript 复制代码
fetch('https://example.com/data')
  .then(response => {
    if(response.ok) {
      return response.json(); // Assuming the response is JSON
    }
    throw new Error('Network response was not ok.');
  })
  .then(data => console.log(data))
  .catch(error => console.error('Fetch error:', error));

在上述代码中,fetch函数调用返回了一个Promise,当响应到达且成功时,则进入.then方法处理,如果有错误则在.catch中处理。

获取Fetch请求进度

由于Fetch返回的Response对象并不直接暴露原始数据流的读取进度。但是,Response对象的body属性是一个ReadableStream,可以用来读取数据流。

要获得Fetch请求的进度,可以通过读取数据流中的chunk大小来估计进度。

javascript 复制代码
fetch('https://example.com/data')
  .then(response => {
    const contentLength = response.headers.get('Content-Length');
    let receivedLength = 0; // received that many bytes at the moment
    let reader = response.body.getReader();
    let chunks = []; // array of received binary chunks (comprises the body)

    return new ReadableStream({
      start(controller) {
        function push() {
          // "done" is a Boolean and value a "Uint8Array"
          reader.read().then(({done, value}) => {
            if (done) {
              controller.close();
              return;
            }
            
            chunks.push(value);
            receivedLength += value.length;
            
            console.log(`Received ${receivedLength} of ${contentLength}`);
            
            // Enqueue the next data chunk into our target stream
            controller.enqueue(value);
            push();
          });
        }
        
        push();
      }
    });
  })
  .then(stream => new Response(stream))
  .then(response => response.blob())
  .then(blob => console.log(blob)) // Do whatever with the blob
  .catch(error => console.error('Fetch error:', error));

在这个示例中,ReadableStream被用来处理原始数据流。response.body.getReader().read()返回了数据块,随着数据块的接收,可以计算已经接收的总数据量receivedLength以及估算进度。

XMLHttpRequest基础

XMLHttpRequest是一个老牌技术,但仍被广泛用于浏览器中执行网络请求。

以下是XHR的基本用法:

javascript 复制代码
let xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data', true);

xhr.onload = function() {
  if (xhr.status === 200) {
    let data = JSON.parse(xhr.responseText);
    console.log(data);
  } else {
    console.error('Request failed. Returned status of ' + xhr.status);
  }
};

xhr.send();

在上述代码段中,首先创建了一个新的XMLHttpRequest对象,然后通过.open()方法初始化了一个请求。在.onload处理函数中处理响应,并在.onerror中处理可能发生的错误。

获取XHR请求进度

与Fetch API不同,XHR提供了progress事件,可用于追踪请求的进度。

javascript 复制代码
let xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data', true);

xhr.onprogress = function(event) {
  if (event.lengthComputable) {
    let percentComplete = (event.loaded / event.total) * 100;
    console.log(`Progress: ${percentComplete}%`);
  }
};

xhr.onload = function() {
  // The request is complete and data is available in `xhr.responseText`
};

xhr.onerror = function() {
  console.error('Request failed');
};

xhr.send();

在上面的代码中,.onprogress事件处理器可以获取当前进度。event.loaded是已下载的字节数,而event.total是总字节数(如果lengthComputable为true)。

使用XHR进行文件上传并获取进度

XHR在上传文件时可以追踪上传进度。以下是xhr上传文件并获取进度的示例:

javascript 复制代码
let file = document.getElementById('fileupload').files[0]; // Assuming <input type="file" id="fileupload">
let xhr = new XMLHttpRequest();
let formData = new FormData();

formData.append('file', file);

xhr.upload.onprogress = function(event) {
  if (event.lengthComputable) {
    let percentComplete = (event.loaded / event.total) * 100;
    console.log(`Upload Progress: ${percentComplete}%`);
  }
};

xhr.onload = function() {
  if (xhr.status === 200) {
    console.log('File successfully uploaded');
  } else {
    console.error('Upload failed. Returned status of ' + xhr.status);
  }
};

xhr.onerror = function() {
  console.error('Upload failed.');
};

xhr.open('POST', 'https://example.com/upload', true);
xhr.send(formData);

上述示例中,FormData用于构建一个表单数据对象。xhr.upload对象允许绑定progress事件,从而追踪上传进度。

为什么Fetch无法获取上传进度

Fetch API目前在规范中并不支持上传进度的监控。fetch()函数返回的Promise直到请求完成后才会解决,且不提供中间状态的信息。由于Fetch API的设计偏向提供一套流式的数据处理方式,而对请求中的状态管理并不直接提供支持。

开发者可以使用Service Worker技术或可观察对象(Observables)作为替代方案来一定程度上监控上传进度,但这些方法实现起来相对复杂,没有XHR在这方面的原生优势。

总结

理解并实现网络请求进度的监控,对于创建友好的用户体验至关重要。通过使用XMLHttpRequestprogress事件或利用Fetch API的ReadableStream接口,开发者可以为用户提供实时反馈,增强其对应用的信心和满意度。此外,在文件上传场景下,由于Fetch API存在一定的限制,XHR提供了一个更为适合的选择,以准确获取上传进度。尽管这些技术各有优劣,但选择合适的方法对网络请求进度的监控可以显著改善网页应用的互动性。在未来,随着Web标准的发展,Fetch API有可能增加更完善的监控传输进度的功能,但截止目前,XHR仍是追踪进度的首选工具。

相关推荐
fg_4111 分钟前
无网络安装ionic和运行
前端·npm
理想不理想v3 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云13 分钟前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:1379712058715 分钟前
web端手机录音
前端
齐 飞21 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
神仙别闹38 分钟前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
aPurpleBerry1 小时前
JS常用数组方法 reduce filter find forEach
javascript
GIS程序媛—椰子1 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_0012 小时前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试