当用户导航到其他页面时,如何中止挂起的jQuery Ajax请求?

4
我已经定义了一个发送jQuery Ajax请求的方法,如下所示。
sendAjaxRequest(URL, data) {
    return $.ajax({
        type        : 'POST',
        url         : URL,
        crossDomain : true,
        data        : JSON.stringify(data),
        dataType    : 'json'
    }).fail((responseData) => {
        if (responseData.responseCode) {
            console.error(responseData.responseCode);
        }
    });
}

我从调用的位置保留了 AJAX 调用的引用。

this.ajaxRequest = sendAjaxRequest(Url, data);

如果用户通过路由转到同一网站上的另一个页面,我希望根据用户导航取消任何待处理的ajax请求。

从文档中我发现jquery jqXHR对象有一个abort方法来取消任何ajax请求。但是在我的ajaxRequest对象中,我没有任何可用的这样的方法。我正在使用jquery 2.2

为了澄清,我还想补充说明我正在使用react,并且希望实现这个功能。

  componentDidMount: function() {
    this.serverRequest = $.get(this.props.source, function (result) {
      var lastGist = result[0];
      this.setState({
        username: lastGist.owner.login,
        lastGistUrl: lastGist.html_url
      });
    }.bind(this));
  },

  componentWillUnmount: function() {
    this.serverRequest.abort();
  },

来源于该链接

他们基本上说,当异步获取数据时,在组件卸载之前使用componentWillUnmount取消所有未完成的请求。

我一定做错了什么。感谢任何帮助。


2
浏览器将自动为您执行此操作。请注意,请求仍将被发送并由服务器处理。abort() 所做的只是停止浏览器监听响应。 - Rory McCrossan
@RoryMcCrossan:“浏览器会自动为您执行此操作。”我不知道切换到不同的选项卡会自动中止先前选项卡上的ajax请求。 - guest271314
3
只有在页面卸载时才能生效,而无法在更改活动浏览器选项卡时生效。 - Rory McCrossan
@RoryMcCrossan 我想这可能是一次误解。OP,你是指使用React Router导航离开当前页面还是跳转到完全不同的互联网页面? - azium
2
其他网页是如何提供服务的?我之所以问,是因为如果您正在获取新的HTML页面,componentWillUnmount甚至都不会运行...这不是React Router或某种历史API吗? - azium
显示剩余9条评论
4个回答

5
根据ajax文档,你正在正确地进行。 $.ajax()函数返回一个具有abort函数的对象。您应该检查函数是否存在,因为如果请求已经完成,则可能不存在该函数。
componentWillUnmount: function(){
  if (this.ajaxRequest && this.ajaxRequest.abort){
    this.ajaxRequest.abort()
  }
}

http://api.jquery.com/jquery.ajax/#jqXHR


我已经使用jQuery编写了很多代码,从未遇到过没有abort()方法或者有了却又失去的jqXHR对象。我还阅读了jQuery的代码以模拟它对jqXHR的处理,但没有看到任何在查询完成后删除abort()的地方。你能提供一个说明这种行为的案例或指出jQuery删除abort()的代码行吗? - Louis
jQuery永远不会删除abort函数,但我认为不能保证this.ajaxRequest一直是jqXHR对象而非nullundefined - Blair Anderson

2
请不要在这种情况下尝试终止 AJAX 请求。更好的方法是如果组件已卸载,则不执行任何操作。看一下这个例子:
componentDidMount: function() {
  // Register to the handler
  this._requestSuccess = this.requestSuccess.bind(this); 
  $.get(this.props.source, this.requestSuccess);
},

componentWillUnmount: function() {
  // "Unregister" by assign it to an empty function
  this._requestSuccess = () => {};
 },

requestSuccess(lastGist) {
  // Do your work
  this.setState({
    username: lastGist.owner.login,
    lastGistUrl: lastGist.html_url
  });
},

在大局观中,不仅是 Ajax 请求,任何可能 改变组件状态 的异步操作都应该在componentDidMount中进行注册,并在componentWillUnmount注销,否则你会发现自己陷入了一团乱麻的异步操作。

在上面的例子中,我使用了 this._requestSuccess = ...; 来注册,然后使用 this._requestSuccess = () => {}; 来注销处理程序,但在实际的应用程序中,你会看到人们使用 FluxRedux 来完成同样的事情。

我强烈建议您使用其中之一来管理您的应用程序数据流,而不仅仅是随处发送和取消 Ajax 请求。


1

请查看fiddle。运行fiddle并检查网络选项卡。

$('button').on('click', function() {
  var _ajax = $.ajax({
    type: 'POST',
    url: "yourURL",
    crossDomain: true,
    data: JSON.stringify('hello'),
    dataType: 'json'
  }).fail((responseData) => {
    if (responseData.responseCode) {
      console.error(responseData.responseCode);
    }
  });
  _ajax.abort();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<button>
  Click me
</button>

ajax变量将保存所有与ajax相关的函数,如文档中所示。

0
如果未调用componentWillUnmount,请检查您的路由器配置。
<Route path="/" component={App}>
  <IndexRoute component={Home}/>
  <Route path="invoices/:invoiceId" component={Invoice}/>
  <Route path="accounts/:accountId" component={Account}/>
</Route>

在这个例子中,{App}组件从根节点开始就没有被卸载。当你从/invoices/导航到/invoices/123时,Invoices组件也不会被卸载。
或者你也可以像这样连接到路由器的setRouteLeaveHook
import React from 'react';
import { withRouter } from 'react-router';

const MyComponent = React.creatClass({

  componentDidMount() {
    this.request = $.get( /* ... */ );

    this.props.router.setRouteLeaveHook(this.props.route, (request) => {
      request.abort();
      return true;
    });
  }

/* .... */

});


export default withRouter(MyComponent);

withRoute 在 react-router 2.4.0 中可用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接