Рубрики
Без рубрики

Как создать пользовательскую Fetch API из XMLHTTPREQUEST

Какой у тебя худший кошмар? Это звучало темно, но это не риторический вопрос. Я действительно хочу знать, потому что я собираюсь сказать вам, мой. По пути мы узнаем некоторые вещи, как то, как работает API Fetch, а также работают конструкторы функции. Извините I

Какой у тебя худший кошмар?

Это звучало темно, но это не риторический вопрос. Я действительно хочу знать, потому что я собираюсь сказать вам, мой. По пути мы узнаем некоторые вещи, как то, как работает API Fetch, а также работают конструкторы функции.

Извините, я отвлекаясь, вернемся к моим худшим кошмаре. Если вы задали мне этот вопрос на прошлой неделе, это был бы указанный ниже порядок:

  • Написание синтаксиса Pre-ES6
  • Нет приема API
  • Нет транспортера (Babel/Teamprctry)
  • Дядя Боб сказал, что я разочарование (шучу)

Если ваш список совпадает с шахтом, я должен сказать, что вы очень странный человек. Как повезет Я был призван работать над проектом, который принес в жизнь мой список кошмаров (исключая последний). Я должен был добавить новую функцию к приложению. Это была устаревшая кодовая база, которая использовала чисто синтаксис Pre-ES6 и XMLHTTPREQUEST (ужас) для его запросов AJAX.

Таким образом, в целях совершать опыт PALTable, я решил создать функцию, которая тезисывает все запросы AJAX, я бы делал и разоблачить API, которые имитируют новые Fetch API (Ну не совсем). Это также после того, как я смотрел JavaScript: Новые жесткие части Видео на фантазии Masters, где было дано удивительное объяснение того, как работала Petch API под капотом. Давай начнем.

Во-первых, я должен был посмотреть, как XMLHTTPREQUEST работает. Тогда я начал писать функцию. Моя первая итерация выглядела так:

"use strict";


function fetch() {
  var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

var xhr = new XMLHttpRequest();
  var onFufillment = [];
  var onError = [];
  var onCompletion = [];
  var method = "GET" || options.method;
  xhr.onreadystatechange = function () {
    var _data = this;
    if (this.readyState == 4 && this.status == 200) {
      // Action to be performed when the document is read;
      onFufillment.forEach(function (callback) {
          callback(_data);
      });
     onCompletion.forEach(function (callback) {
        callback(_data);
      });
    } else if (this.readyState == 4 && this.status !== 200) {
      onError.forEach(function (callback) {
        callback(_data);
      });
      onCompletion.forEach(function (callback) {
        callback(_data);
      });
    }
  };
  xhr.open(method, url, true);
  xhr.send();


return {
    then: function then(fufillmentFunction) {
      onFufillment.push(fufillmentFunction);
    },
    catch: function _catch(errorFunction) {
      onError.push(errorFunction);
    },
    finally: function _finally(completionFunction) {
      onCompletion.push(completionFunction);
    }
  };
}

Позвольте мне работать через то, что делает функция:

  • Мы проверяем, если URL аргумент передан в функцию. По умолчанию для пустой строки, если ничего не передано
  • Мы также делаем то же самое для Варианты аргумент По умолчанию для пустого объекта, если ничего не пройдено
  • Затем мы создаем новый экземпляр XMLHTTPREQUEST
  • Мы создаем 4 переменных Onfufillment, OneRror, OnCompletion и метод
  • Onfufillment это массив, который хранит все функции, переданные в тогда метод
  • OneRror это массив что хранит все функции, переданные в поймать метод
  • Осмещение это массив, который хранит все функции, переданные в Наконец метод
  • Метод Используется для хранения метода HTTP, который будет использоваться, по умолчанию для ПОЛУЧАТЬ
  • Затем мы передаем функцию в onreadystatechange метод XHR который будет вызван, когда состояние запроса меняется
  • В функции мы сохраняем Это в _data переменная, так что ее можно передавать в функции foreach, не теряя контекста (я знаю Это раздражает)
  • Затем мы проверяем, завершен ли запрос ( AdvantState ), и если запрос успешен, то мы планируем через Onfufillment и OnCompletion Массивы, вызывая каждую функцию и прохождение _data внутрь
  • Если запрос не удается, мы делаем то же самое с OnComplecletion и OneRror массива
  • Затем мы отправляем запрос с прохожденным параметрам
  • После этого мы возвращаем объект, содержащий три функции, то. поймать и наконец которые имеют такие же имена, как Petch API.
  • поймать толкает функцию, которая передается как аргумент в OneRror множество
  • тогда делает то же самое с Onfufillment множество
  • Наконец делает то же самое с Осмещение множество

Использование этого API будет выглядеть так:

var futureData = fetch('https://jsonplaceholder.typicode.com/todos/2');
futureData.then(function(data){
  console.log(data)
})

futureData.finally(function(response){
  console.log(response);
});

futureData.catch(function(error){
  console.log(error);
})

Оно работает!!! Но не почти как реальная реализация. Можем ли мы сделать лучше, чем это? Конечно можем. Мы все еще можем добавить больше функций в функцию. Мы могли бы сделать это церемонтируемым, то есть мы можем дать ему возможность цепи методов вместе.

На второй итерации, вот как это выглядит:

"use strict";

function fetch() {
  var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var xhr = new XMLHttpRequest();
  var onFufillment = [];
  var onError = [];
  var onCompletion = [];
  var method = "GET" || options.method;
  xhr.onreadystatechange = function () {
    var _data = this;
    if (this.readyState == 4 && this.status == 200) {
      // Action to be performed when the document is read;
      onFufillment.forEach(function (callback) {
          callback(_data);
      });
     onCompletion.forEach(function (callback) {
        callback(_data);
      });
    } else if (this.readyState == 4 && this.status !== 200) {
      onError.forEach(function (callback) {
        callback(_data);
      });
      onCompletion.forEach(function (callback) {
        callback(_data);
      });
    }
  };
  xhr.open(method, url, true);
  xhr.send();


	return {
    	then: function then(fufillmentFunction) {
          onFufillment.push(fufillmentFunction);
          return this;
   		},
    	catch: function _catch(errorFunction) {
      	  onError.push(errorFunction);
      	  return this;
      },
        finally: function _finally(completionFunction) {
         onCompletion.push(completionFunction);
         return this;
    }
  };
}

Использование API будет выглядеть так:

var futureData = fetch('https://jsonplaceholder.typicode.com/todos/2');


futureData.then(function(data){
  console.log(data)
}).then(function(response){
  console.log(response);
}).catch(function(error){
  console.log(error);
});

Что это сделал? Единственная разница во второй итерации была в Тогда поймай и наконец где я только что вернулся Это Это означает, что каждая функция возвращает себя в основном, позволяющая ему быть цепочкой (частично).

Лучше верно? Но мы можем ли мы сделать лучше, чем это? Конечно можем. Возвращенный объект можно поместить в прототип функции, чтобы мы могли сохранить память в ситуации, когда функция используется несколько раз.

Вот как это выглядит на третьей итерации:

"use strict";
function fetch() {
  var fetchMethod = Object.create(fetch.prototype);
  var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var xhr = new XMLHttpRequest();
  fetchMethod.onFufillment = [];
  fetchMethod.onError = [];
  fetchMethod.onCompletion = [];
  var method = "GET" || options.method;
  xhr.onreadystatechange = function () {
    var _data = this;
    if (this.readyState == 4 && this.status == 200) {
      // Action to be performed when the document is read;
      fetchMethod.onFufillment.forEach(function (callback) {
          callback(_data);
      });
     fetchMethod.onCompletion.forEach(function (callback) {
        callback(_data);
      });
    } else if (this.readyState == 4 && this.status !== 200) {
      fetchMethod.onError.forEach(function (callback) {
        callback(_data);
      });
      fetchMethod.onCompletion.forEach(function (callback) {
        callback(_data);
      });
    }
  };
  xhr.open(method, url, true);
  xhr.send();
  return fetchMethod;
};
fetch.prototype.then = function(fufillmentFunction) {
      this.onFufillment.push(fufillmentFunction);
      return this;
};
fetch.prototype.catch = function(errorFunction) {
      this.onError.push(errorFunction);
      return this;
};
fetch.prototype.finally = function(completionFunction) {
      this.onCompletion.push(completionFunction);
      return this;
};

Таким образом, эта версия в основном перемещает возвращенную функцию в прототип Fetch. Если вы не понимаете утверждение, я рекомендую проверить эту статью о Прототип JavaScript (Спасибо, Тайлер Макгиннис).

Это улучшение? Да!!! Можем ли мы сделать лучше? Конечно можем. Мы можем использовать новый Ключевое слово в наше преимущество здесь и удалить явное оператор возврата.

Следующая итерация будет выглядеть так:

"use strict";
function Fetch() {
  var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  var xhr = new XMLHttpRequest();
  this.onFufillment = [];
  this.onError = [];
  this.onCompletion = [];
  var method = "GET" || options.method;
  var internalFetchContext = this;
  xhr.onreadystatechange = function () {
    var _data = this;
    if (this.readyState == 4 && this.status == 200) {
      // Action to be performed when the document is read;
      internalFetchContext.onFufillment.forEach(function (callback) {
          callback(_data);
      });
     internalFetchContext.onCompletion.forEach(function (callback) {
        callback(_data);
      });
    } else if (this.readyState == 4 && this.status !== 200) {
      internalFetchContext.onError.forEach(function (callback) {
        callback(_data);
      });
      internalFetchContext.onCompletion.forEach(function (callback) {
        callback(_data);
      });
    }
  };
  xhr.open(method, url, true);
  xhr.send();
};
Fetch.prototype.then = function(fufillmentFunction) {
      this.onFufillment.push(fufillmentFunction);
      return this;
};
Fetch.prototype.catch = function(errorFunction) {
      this.onError.push(errorFunction);
      return this;
};
Fetch.prototype.finally = function(completionFunction) {
      this.onCompletion.push(completionFunction);
      return this;
};

Позвольте мне объяснить изменения:

  • Изменил имя функции из Fetch, чтобы получить, это просто конвенция при использовании новый ключевое слово
  • Так как я использую Новый ключевое слово Затем я могу сохранить различные массивы, созданные для Это контекст.
  • Потому что функция прошла в onreadystatechange имеет свой собственный контекст, который мне пришлось спасти оригинал Это в свою собственную переменную, чтобы позволить мне позвонить в функцию (я знаю, это можно раздражать)
  • Преобразовал функции прототипа на новое имя функции.

Использование будет выглядеть так:

var futureData = new 

Fetch('https://jsonplaceholder.typicode.com/todos/1');
futureData.then(function(data){
  console.log(data)
}).then(function(response){
  console.log(response);
}).catch(function(error){
  console.log(error);
})

Вуаля! Это было действительно весело. Но мы можем ли мы сделать лучше? Конечно можем.

Но я оставлю это тебе. Я хотел бы увидеть вашу собственную реализацию API в комментариях ниже.

Если вам понравилась статья (и даже если вы этого не сделали), я был бы признателен за хлопья (или 50) от вас. Спасибо.

Оригинал: “https://www.freecodecamp.org/news/create-a-custom-fetch-api-from-xmlhttprequest-2cad1b84f07c/”