首页 > 解决方案 > VanillaJS Promise 实现替换 jQuery 通知/进度事件

问题描述

我目前正在使用一个$.Deferred()对象来发布消息。

当服务器返回错误时,我正在使用notify,然后重试,直到成功或失败X多次。

我想去掉 jQuery 的使用,ant 移到 ES6 相关选项。

我知道如何使用Promise(),但它可以被拒绝或解决,但不能两者兼而有之。

有更好的主意吗?

当前代码:

var def = $.Deferred(),
  data = {
    iTries: 0,
    ....
  };

$.ajax({
  type: "POST",
  url: "POST",
  data: data,
  timeout: 15000,
  success: d => def.resolve(d);,
  error: function(vSocket, status, error) {
    def.notify('error'); // this I want to replace
    data.iTries++;

    //try again
    if (data.iTries < 40) window.setTimeout(function() {
      DoAgain(data, def).then(q => def.resolve(q));
    }, 9000);
    else {
      def.reject();
    }
  }
  else {
    if (data.iTries < 20) window.setTimeout(function() {
      Poll.AjaxPoll(data, def).then(q => def.resolve(q));
    }, 30000);
  }
}
});

标签: javascriptjqueryes6-promise

解决方案


从您的代码看来,您正在使用 ES6(您正在使用箭头函数)。您可以使用 es6 箭头函数和承诺遵循递归方法,它可能是这样的:

doAjaxRequest(data) {
    fireAPICall(data).then(response => { // fireAPICall is a method that fires the post request and returns the response received from server
        if(response.status == 200) { // success (this if statement is optional)
            // handle success
            let d = response.data;
        }
    }).catch(error => { // failure
        data.iTries++;
        if(data.iTries < 40) {
            window.setTimeout(() => {doAjaxRequest(data)}, 9000); // try again
        } else if(data.iTries < 20) {
            window.setTimeout(() => {doAjaxRequest(data)}, 30000); // try again
        }
    });
}

对于该fireAPICall方法,您可以使用任何基于 Promise 的 http 客户端,例如axiosFetch API,这里我使用的是axios

fireAPICall(data) {
    return axios.post("url", data);
}

更新:如果您想同时处理reject/failure事件和notify/progress事件,这将需要一些服务器端协作。202如果发生进度事件(尚未准备好),您可以让服务器返回状态代码(或任何其他更合适的状态代码),您可以在.then()回调中处理它:

doAjaxRequest(data) {
    fireAPICall(data).then(response => { // fireAPICall is a method that fires the post request and returns the response received from server
        if(response.status === 202) { // notify/progress event
            data.iTries++;
            if(data.iTries < 40) {
                window.setTimeout(() => {doAjaxRequest(data)}, 9000); // try again
            } else if(data.iTries < 20) {
                window.setTimeout(() => {doAjaxRequest(data)}, 30000); // try again
            } else {
                return Promise.reject('poll eneded with no success'); // exceeded maximum number of times for polling, so reject. This will invoke the catch callback method with this error
            }
        } else { // handle success
            let d = response.data;
        }
    }).catch(error => { // reject/failure for some other reason
        // handle error
    });
}

推荐阅读