XHR как Promise

Цель: упростить использование xhrRequest. Хочется, чтобы можно было просто передать набор параметров и получить в качестве ответа Promise. В итоге должен получиться некий аналог fetch. Также хочется иметь reject по таймауту, если сервер долго не отвечает.

Для этого оборачиваем xhrRequest в Promise. Парметры соединения передаем как объект. Чтобы можно было в вызывающем методе не перечислять все параметры, создаем дефолтный набор и с помощью Object.assign добавляем из него недостающие значения.

После отправки запроса запускаем таймер, также обернув его в Promise, и возвращаем в результате что сработает быстрее (Promise.race).

'use strict';

export function uxRequest(params, timeout = 5000) {

  const xhrPromise = new Promise((resolve, reject) => {  

    params = Object.assign({
      'url': '', 
      'data': '', 
      'method': 'POST', 
      'headers': {},
      'credentials': false,
      'responseType':false
      },params);

    //if not url
    if (!params.url) reject({
      'description': 'not url'    
    });

    let xhr = new XMLHttpRequest();
    
    xhr.open(params.method, params.url);

    //adding headers
    for(let key in params.headers){
      xhr.setRequestHeader(key, params.headers[key]) 
    }
    
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    
    if (params.credentials) {
      xhr.withCredentials = true;
    }
    
    xhr.onreadystatechange = () => {

      if (xhr.readyState != 4) return;//do nothing

      if (xhr.status == 200) {
        resolve(xhr);
      } else {
        reject({
          'status': xhr.status,
          'statusText': xhr.statusText,
          'description': 'response error'
        });
      }
    };

    xhr.onerror = () => {
      reject({
        'status': xhr.status,
        'statusText': xhr.statusText,
        'description': 'load error'
      });
    };
    
    if (params.responseType) {
      //if response must be BLOB
      if (params.responseType == 'blob') {
        xhr.responseType = "arraybuffer";
      } else {
        xhr.responseType = params.responseType;
      }
    }
    
    xhr.send(params.data);
  });

  const timeoutPromise = new Promise((resolve, reject) => {
    console.log('timeout start');
    let id = setTimeout(() => {
      console.log('timeout end');
      clearTimeout(id);
      reject({
        'description': 'timeout',
        'code':  504    
      })
    }, timeout)
  })

  return Promise.race([
    xhrPromise,
    timeoutPromise
  ]);
}


Использование:

let data = new FormData();
data.append('param1', value1);
data.append('param2', value2);
uxRequest({
  'url': '/path/to/script/', 
  'data': data
}).then(
    (result) => {
    //parse JSON
    let object = JSON.parse(result);
    //do something
  }    
)
.catch((err) => console.log('Augh, there was an error!', err));