【问题标题】:Converting jQuery ajax to fetch将 jQuery ajax 转换为 fetch
【发布时间】:2021-06-13 08:10:10
【问题描述】:

我有这段代码调用函数 getTableData 并期望得到一个 Promise 作为回报。

function populateTableRows(url) {
  successCallback = () => { ... };
  errorCallback = () => { ... };

  getTableData(url, successCallback, errorCallback).then(tableData => {
    // do stuff with tableData
  }
}

这在我的代码库中的许多地方都使用过,我希望在不再使用 jQuery 的 ajax(以及一般的 jQuery)时保持相同的行为

在 getTableData 中,我目前正在使用$.ajax,就像这样

function getTableData(url, successCallback, errorCallback) {
  successCallback = successCallback || function() {};
  errorCallback = errorCallback || function() {};

  const ajaxOptions = {
    type: 'POST',
    url: url,
    dataType: 'json',
    xhrFields: {
      withCredentials: true
    },
    crossDomain: true,
    data: { // some data }
  };

  return $.ajax(ajaxOptions).done(successCallback).fail(errorCallback);
}

这当前会为成功的请求返回一个 Promise。对于调用 fail 的错误请求,似乎没有返回 Promise 并且 then 没有在调用函数中运行(在这种情况下没问题)。

将请求转换为使用 fetch 时,我有这样的事情

function getTableData(url, successCallback, errorCallback) {
  successCallback = successCallback || function() {};
  errorCallback = errorCallback || function() {};
  return fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    credentials: 'include',
    body: { // some data }
  })
  .then(response => {
    let json = response.json();
    if (response.status >= 200 && response.status < 300) {
      successCallback(json);
      return json;
    } else {
      return json.then(error => {throw error;});
    }
  }).catch((error) => {
    errorCallback(error);
    return
  });

成功的请求似乎与我目前拥有的 ajax 代码的行为相似,但现在 then 回调正在针对导致我的代码出错的错误请求运行。

fetch 有没有办法模仿 jQuery 的 fail 行为,其中 Promise 似乎因错误请求而中止?我对使用 Promises 还很陌生,经过一些实验/搜索后,我无法提出解决方案。

【问题讨论】:

  • 寻找response.ok
  • 是的,fetch MDN 专门解决 jquery.ajax 的差异: fetch 规范与 jQuery.ajax() 在以下重要方面不同: 从 fetch() 返回的 Promise 不会拒绝 HTTP 错误状态即使响应是 HTTP 404 或 500。相反,只要服务器响应标头,Promise 就会正常解析(如果响应不在 200–299 范围内,则响应的 ok 属性设置为 false ),并且它只会在网络故障或任何阻止请求完成的情况下拒绝。

标签: javascript jquery ajax fetch


【解决方案1】:

在您的.catch 中,您隐式返回 undefined 并因此“处理”错误。结果是一个新的 Promise,履行undefined

  .catch((error) => {
    errorCallback(error);
    return Promise.reject();
  });

应该足以让返回的 Promise 被拒绝。

或者您将中间 Promise 分配给一个 var 并将其返回,而不是将结果返回给失败处理:

  var reqPromise = fetch(url, {
    // ...
  })
  .then(response => {
    // ...
      return json.then(error => {throw error;});
  });
  
  reqPromise.catch((error) => {
    errorCallback(error);
    return
  });
  
  return reqPromise;

【讨论】:

  • 谢谢!我尝试了类似于您提到的返回被拒绝的承诺的方法。我在控制台中收到“未捕获(承诺)”错误,我在提供的两种解决方案中也看到了这种错误。这似乎没有问题,但我很好奇是否有办法处理这些问题?
  • jQuery 的 Promise (Deferred) 实现与原生 ES6 Promise (stackoverflow.com/a/32832019/7362396) 不同。这就是为什么你没有在那里看到它。您需要 .catch 或注册 developer.mozilla.org/en-US/docs/Web/API/Window/… unhandledrejection 处理程序来抑制。
【解决方案2】:

当你 .catch() 在一系列承诺中时,这意味着你已经处理了错误,后续的 .then() 调用会继续成功。

例如:

apiCall()
  .catch((error) => {
    console.log(error);
    return true; // error handled, returning true here means the promise chain can continue
  })
  .then(() => {
    console.log('still executing if the API call fails');
  });

在你的情况下,你想要的是当你用回调处理错误时,继续抛出它,这样承诺链就会被破坏。然后链进一步需要一个新的.catch() 块来处理新的错误。

apiCall()
  .catch((error) => {
    console.log(error); // "handled", but we're still not done
    throw error; // instead of returning true, we throw the error further
    // ? this can also be written as `return Promise.reject(error);`
  })
  .then(() => {
    console.log('not executing anymore if the API call fails');
  })
  .catch((error) => {
    // handle the same error we have thrown from the previous catch block
    return true; // not throwing anymore, so error is handled
  })
  .then(() => {
    console.log('always executing, since we returned true in the last catch block');
  });

顺便说一句,你从一个 then/catch 块返回的内容,后面的将把它作为参数。

apiCall()
  .then((response) => {
    /* do something with response */;
    return 1;
  })
  .catch((error) => { return 'a'; })
  .then((x) => console.log(x)) // x is 'a' if there's an error in the API call, or `1` otherwise

【讨论】:

  • 感谢您的意见!这提供了丰富的信息,帮助我更好地了解 Promise 链的运作方式,但这并不是我想要的。
猜你喜欢
  • 2018-12-04
  • 2021-12-29
  • 2018-01-26
  • 2018-04-26
  • 2019-12-17
  • 1970-01-01
  • 2018-03-29
  • 2022-11-27
  • 2016-04-09
相关资源
最近更新 更多