VanillaJS Promise实现替换jQuery notify / progress事件

时间:2018-12-29 16:28:36

标签: javascript jquery es6-promise

我当前正在使用$.Deferred()对象发布消息。

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

我想删除jQuery的用法,并转到与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);
  }
}
});

2 个答案:

答案 0 :(得分:1)

从您的代码看来,您正在使用ES6(正在使用箭头功能)。您可以使用带有es6箭头功能和promises的递归方法,可能是这样的:

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方法,您可以使用任何基于承诺的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
    });
}

答案 1 :(得分:0)

正如您所说,承诺只能一次被兑现。 (jQuery的$.Deferred也是这样,[现在]大部分都是诺言。)

定期通知不是诺言的用例。相反,您需要某种事件发射器或发布/订阅系统(对于jQuery,有相同的极端小型系统,例如this one [非背书]),甚至只是回调您打电话来了解进度更新。

相关问题