Я хочу использовать (родные) обещания в моем приложении для выполнения запроса XHR, но без всякой дурачества массивной платформы.
Я хочу , чтобы мой XHR вернуть обещание , но это не работает (давая мне: Uncaught TypeError: Promise resolver undefined is not a function
)
function makeXHRRequest (method, url, done) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function() { return new Promise().resolve(); };
xhr.onerror = function() { return new Promise().reject(); };
xhr.send();
}
makeXHRRequest('GET', 'http://example.com')
.then(function (datums) {
console.log(datums);
});
javascript
xmlhttprequest
promise
SomeKittens
источник
источник
Ответы:
Я предполагаю, что вы знаете, как сделать собственный запрос XHR (вы можете освежить здесь и здесь )
Поскольку любой браузер, который поддерживает собственные обещания , также будет поддерживать
xhr.onload
, мы можем пропустить всеonReadyStateChange
дурачества. Давайте сделаем шаг назад и начнем с базовой функции запроса XHR, используя обратные вызовы:Ура! В этом нет ничего ужасно сложного (например, пользовательских заголовков или данных POST), но этого достаточно, чтобы продвинуться вперед.
Конструктор обещаний
Мы можем построить обещание так:
Конструктор обещаний принимает функцию, которой будут переданы два аргумента (назовем их
resolve
иreject
). Вы можете думать об этом как о обратных вызовах, один для успеха и один для отказа. Примеры потрясающие, давайте обновимсяmakeRequest
этим конструктором:Теперь мы можем использовать силу обещаний, объединяя несколько вызовов XHR (и при
.catch
каждом вызове будет вызывать ошибку):Мы можем улучшить это еще больше, добавив как параметры POST / PUT, так и пользовательские заголовки. Давайте использовать объект параметров вместо нескольких аргументов с подписью:
makeRequest
теперь выглядит примерно так:Более комплексный подход можно найти в MDN .
Кроме того, вы можете использовать API выборки ( polyfill ).
источник
responseType
аутентификации, учетных данныхtimeout
и т. Д. Иparams
объекты должны поддерживать BLOB-объекты / просмотры буферов иFormData
экземплярыxhr.status
иxhr.statusText
при ошибке, так как они пусты в этом случае.resolve(xhr.response | xhr.responseText);
В большинстве браузеров следует использовать repsonse в формате responseText.Это может быть так же просто, как следующий код.
Имейте в виду, что этот код будет вызывать
reject
обратный вызов только приonerror
вызове ( только сетевые ошибки), а не тогда, когда код состояния HTTP означает ошибку. Это также исключит все другие исключения. Обработка этих вопросов должна решать вам, ИМО.Кроме того, рекомендуется вызывать
reject
обратный вызов с экземпляром,Error
а не с самим событием, но для простоты я оставил как есть.И вызывать это можно так:
источник
xhr.send(requestBody)
Для тех, кто ищет это сейчас, вы можете использовать функцию извлечения . У него довольно хорошая поддержка .
Сначала я использовал ответ @ SomeKittens, но потом обнаружил,
fetch
что он делает это для меня из коробки :)источник
fetch
функцию, но GitHub опубликовал полифилл .fetch
как он пока не поддерживает отмену.Я думаю, что мы можем сделать верхний ответ гораздо более гибким и пригодным для повторного использования, не создавая
XMLHttpRequest
объект. Единственная выгода от этого заключается в том, что нам не нужно самостоятельно писать 2 или 3 строки кода, и это имеет огромный недостаток, заключающийся в лишении нашего доступа ко многим функциям API, таким как установка заголовков. Он также скрывает свойства исходного объекта от кода, который должен обрабатывать ответ (как для успехов, так и для ошибок). Таким образом, мы можем сделать более гибкую, более широко применимую функцию, просто принимаяXMLHttpRequest
объект в качестве входных данных и передавая его в качестве результата .Эта функция преобразует произвольный
XMLHttpRequest
объект в обещание, обрабатывая коды состояния, отличные от 200, по умолчанию как ошибку:Эта функция очень естественно вписывается в цепочку
Promise
s, не жертвуя гибкостьюXMLHttpRequest
API:catch
был опущен выше для упрощения примера кода. У вас всегда должен быть один, и, конечно, мы можем:А отключение обработки кода состояния HTTP не требует больших изменений в коде:
Наш код вызова длиннее, но концептуально все еще просто понять, что происходит. И нам не нужно перестраивать весь API веб-запросов только для поддержки его функций.
Мы также можем добавить несколько удобных функций, чтобы привести в порядок наш код:
Тогда наш код становится:
источник
На мой взгляд, ответ jpmc26 довольно близок к идеальному. Однако у него есть некоторые недостатки:
POST
-requests устанавливать тело запроса.send
вызов скрыт внутри функции.Обезьяна, исправляющая объект xhr, решает следующие проблемы:
Теперь использование так же просто, как:
Конечно, это вносит другой недостаток: исправление обезьяны снижает производительность. Однако это не должно быть проблемой, если предположить, что пользователь ожидает в основном результата xhr, что сам запрос занимает на несколько порядков больше времени, чем настройка вызова, и запросы xhr отправляются не часто.
PS: И конечно, если вы ориентируетесь на современные браузеры, используйте fetch!
PPS: в комментариях было указано, что этот метод изменяет стандартный API, что может сбивать с толку. Для большей наглядности можно применить другой метод к объекту xhr
sendAndGetPromise()
.источник
send
вызов, но также может запутать читателей, которые знают, чтоsend
не имеют возвращаемого значения. Использование более явных вызовов проясняет, что была вызвана дополнительная логика. Мой ответ должен быть скорректирован для обработки аргументовsend
; однако, вероятно, лучше использоватьfetch
сейчас.