获取网络通信进度实践

网络请求是现代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仍是追踪进度的首选工具。

相关推荐
霍先生的虚拟宇宙网络24 分钟前
webp 网页如何录屏?
开发语言·前端·javascript
温吞-ing26 分钟前
第十章JavaScript的应用
开发语言·javascript·ecmascript
彪82527 分钟前
第十章 JavaScript的应用 习题
javascript·css·ecmascript·html5
jessezappy44 分钟前
jQuery-Word-Export 使用记录及完整修正文件下载 jquery.wordexport.js
前端·word·jquery·filesaver·word-export
旧林8431 小时前
第八章 利用CSS制作导航菜单
前端·css
yngsqq1 小时前
c#使用高版本8.0步骤
java·前端·c#
Myli_ing2 小时前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风2 小时前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave2 小时前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟2 小时前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js