获取网络通信进度实践

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

Fetch基础

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

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大小来估计进度。

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的基本用法:

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事件,可用于追踪请求的进度。

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上传文件并获取进度的示例:

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仍是追踪进度的首选工具。

原文链接:https://juejin.cn/post/7313911715854155816 作者:慕仲卿

(0)
上一篇 2023年12月19日 下午4:52
下一篇 2023年12月19日 下午5:02

相关推荐

发表回复

登录后才能评论