Какой у тебя худший кошмар?
Это звучало темно, но это не риторический вопрос. Я действительно хочу знать, потому что я собираюсь сказать вам, мой. По пути мы узнаем некоторые вещи, как то, как работает 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/”