XMLHttpRequest和fetch

643 阅读2分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战

XMLHttpRequest

基本用法

let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');

// request state change event
xhr.onreadystatechange = function() {
  // request completed?
  if (xhr.readyState !== 4) return;

  if (xhr.status === 200) {
    // request successful - show response
    console.log(xhr.responseText);
  } else {
    // request error
    console.log('HTTP error', xhr.status, xhr.statusText);
  }
};

// start request
xhr.send();

设置超时timeout

xhr.timeout = 3000; // 3 seconds
xhr.ontimeout = () => console.log('timeout', xhr.responseURL);

文件上传进度

xhr.upload.onprogress = p => {
  console.log( Math.round((p.loaded / p.total) * 100) + '%') ;
}

缺点

其属性很多,比较复杂

Fetch

基本用法

Fetch APIXMLHttpRequest的现代替代方案。通用的HeaderRequestResponse接口提供了一致性,同时Promises允许更简单的的链式调用和不需要回调的async/await。

简洁,优雅,易于理解。

fetch(
    'http://domain/service',
    { method: 'GET' }
  )
  .then( response => response.json() )
  .then( json => console.log(json) )
  .catch( error => console.error('error:', error) );

缺点

默认无Cookie

通过修改第二个参数中的初始值来解决。

fetch(
  'http://domain/service',
  {
    method: 'GET',
    credentials: 'same-origin'
  }
)

错误不会拒绝

HTTP错误时,不会让Fetch返回Promise标记为reject,.catch()也不会被执行。想要精确的判断fetch是否成功,需要在resolve的情况,再判断response.ok是否为true。

fetch(
    'http://domain/service', 
    { method: 'GET' }
  )
  .then( response => {
    if(response.ok) {
      return response.json();
    }
    throw new Error('Network response was not ok.');
  })
  .then( json => console.log(json) )
  .catch( error => console.error('error:', error) );

当请求无法完成才会触发reject。如:网络中断,请求被阻止。错误捕获会变得复杂

不支持超时

用Promise.race()设置超时

Promise.race([
  fetch('http://url', { method: 'GET' }),
  new Promise(resolve => setTimeout(resolve, 3000))
])
  .then(response => console.log(response))。

早期不支持终止

早期无法终止,现在实现了AbortController API的浏览器可以终止。

const controller = new AbortController();

fetch(
  'http://domain/service',
  {
    method: 'GET'
    signal: controller.signal
  })
  .then( response => response.json() )
  .then( json => console.log(json) )
  .catch( error => console.error('Error:', error) );

Fetch可以通过调用controller.abort()来中止。Promise被标记reject后,会调用.catch()函数。

没有Progress

不能显示文件上传和大型表单提交的进度

XMLHttpRequest vs Fetch?

目前已XMLHttpRequest为主,但它比较复杂,使用时需要再做封装。

Fetch更为简单方便,同时也省去了一些功能,如果把功能通过其他方式完成,那其也会变得复杂。

Fetch未来可期!!!