我如何宣传原生XHR? [英] How do I promisify native XHR?

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

问题描述

我想在我的前端应用程序中使用(本机)promises来执行XHR请求,但没有庞大框架的所有tomfoolery。

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

我希望我的xhr返回承诺,但这不起作用(给我:未捕获TypeError:承诺解析器未定义不是函数

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)

由于支持本机承诺的任何浏览器也将支持 xhr.onload ,我们可以跳过所有 onReadyStateChange tomfoolery。让我们退后一步,使用回调函数从基本的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);
});

Hurray!这不涉及任何非常复杂的事情(如自定义标题或POST数据),但足以让我们向前移动。

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

我们可以像这样构建一个承诺:

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构造函数接受一个将传递两个参数的函数(让我们称之为解决拒绝)。您可以将这些视为回调,一个用于成功,一个用于失败。示例很棒,让我们用这个构造函数更新 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);
});

现在我们可以利用承诺的力量,链接多个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

或者,您可以使用获取API polyfill )。

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

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

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