我如何承诺原生 XHR? [英] How do I promisify native XHR?

查看:19
本文介绍了我如何承诺原生 XHR?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的前端应用程序中使用(原生)promise 来执行 XHR 请求,但没有大型框架的所有愚蠢行为.

I want to use (native) promises in my frontend app to perform XHR request but without all the tomfoolery of a massive framework.

我希望我的 xhr 返回一个承诺,但这不起作用(给我:Uncaught TypeError: Promise resolver undefined is not a function)

I want my xhr to return a promise but this doesn't work (giving me: 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);
});

推荐答案

我假设你知道如何进行原生 XHR 请求(你可以刷一下 此处此处)

I'm assuming you know how to make a native XHR request (you can brush up here and here)

由于 任何支持原生 promises 的浏览器 也将支持 xhr.onload,我们可以跳过所有的 onReadyStateChange 傻瓜.让我们退后一步,从使用回调的基本 XHR 请求函数开始:

Since any browser that supports native promises will also support xhr.onload, we can skip all the onReadyStateChange tomfoolery. Let's take a step back and start with a basic XHR request function using callbacks:

function makeRequest (method, url, done) {
  var xhr = new XMLHttpRequest();
  xhr.open(method, url);
  xhr.onload = function () {
    done(null, xhr.response);
  };
  xhr.onerror = function () {
    done(xhr.response);
  };
  xhr.send();
}

// And we'd call it as such:

makeRequest('GET', 'http://example.com', function (err, datums) {
  if (err) { throw err; }
  console.log(datums);
});

万岁!这不涉及任何非常复杂的事情(如自定义标头或 POST 数据),但足以让我们继续前进.

Hurrah! This doesn't involve anything terribly complicated (like custom headers or POST data) but is enough to get us moving forwards.

我们可以像这样构造一个 promise:

We can construct a promise like so:

new Promise(function (resolve, reject) {
  // Do some Async stuff
  // call resolve if it succeeded
  // reject if it failed
});

promise 构造函数接受一个函数,该函数将传递两个参数(我们称它们为 resolvereject).您可以将这些视为回调,一个表示成功,一个表示失败.例子很棒,让我们用这个构造函数更新 makeRequest :

The promise constructor takes a function that will be passed two arguments (let's call them resolve and reject). You can think of these as callbacks, one for success and one for failure. Examples are awesome, let's update makeRequest with this constructor:

function makeRequest (method, url) {
  return new Promise(function (resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(xhr.response);
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    xhr.send();
  });
}

// Example:

makeRequest('GET', 'http://example.com')
.then(function (datums) {
  console.log(datums);
})
.catch(function (err) {
  console.error('Augh, there was an error!', err.statusText);
});

现在我们可以利用 promises 的力量,链接多个 XHR 调用(并且 .catch 将在任一调用中触发错误):

Now we can tap into the power of promises, chaining multiple XHR calls (and the .catch will trigger for an error on either call):

makeRequest('GET', 'http://example.com')
.then(function (datums) {
  return makeRequest('GET', datums.url);
})
.then(function (moreDatums) {
  console.log(moreDatums);
})
.catch(function (err) {
  console.error('Augh, there was an error!', err.statusText);
});

我们可以进一步改进这一点,添加 POST/PUT 参数和自定义标头.让我们使用带有签名的选项对象而不是多个参数:

We can improve this still further, adding both POST/PUT params and custom headers. Let's use an options object instead of multiple arguments, with the signature:

{
  method: String,
  url: String,
  params: String | Object,
  headers: Object
}

makeRequest 现在看起来像这样:

function makeRequest (opts) {
  return new Promise(function (resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open(opts.method, opts.url);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(xhr.response);
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    if (opts.headers) {
      Object.keys(opts.headers).forEach(function (key) {
        xhr.setRequestHeader(key, opts.headers[key]);
      });
    }
    var params = opts.params;
    // We'll need to stringify if we've been given an object
    // If we have a string, this is skipped.
    if (params && typeof params === 'object') {
      params = Object.keys(params).map(function (key) {
        return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
      }).join('&');
    }
    xhr.send(params);
  });
}

// Headers and params are optional
makeRequest({
  method: 'GET',
  url: 'http://example.com'
})
.then(function (datums) {
  return makeRequest({
    method: 'POST',
    url: datums.url,
    params: {
      score: 9001
    },
    headers: {
      'X-Subliminal-Message': 'Upvote-this-answer'
    }
  });
})
.catch(function (err) {
  console.error('Augh, there was an error!', err.statusText);
});

更全面的方法可以在 MDN.

A more comprehensive approach can be found at MDN.

或者,您可以使用 fetch API(polyfill).

Alternatively, you could use the fetch API (polyfill).

这篇关于我如何承诺原生 XHR?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆