即使我在所有 then-able 中使用拒绝回调,我是否总是需要在最后需要 catch()

Do I always need catch() at the end even if I use a reject callback in all then-ables?

本文关键字:是否 catch 最后 回调 then-able 拒绝      更新时间:2023-09-26

我把捕获放在最后,但它们至少在一个特定的实例中返回空对象。对于任何未知的事情都需要捕获,还是只是把我搞砸了?

$( document).ready(function(){
    app.callAPI()//a chainable a RSVP wrapper around a jquery call, with its own success() fail() passing forward to the wrapper, so it will either be a resolved or rejected thenable to which is now going to be chained 
        .then(
            function(env) {
                //set the property you needed now
                app.someSpecialEnvObj = env;
            },
            function(rejectMessage){
                console.log('call.API() cant set some special env object..');
                console.log(rejectMessage);
            }
        )
        .catch(
        function(rejectMessage){
            if(rejectMessage){
                //a just incase, DOES IT HAVE VALUE, for somebody that may have not done their homework in the parent calls?
                console.log('you have some kind of legitimate error, maybe even in callAPI() that is not part of any problems inside them.  you may have forgotton handle something at an early state, your so lucky this is here!)
            } else {
                console.log('can this, and or will this ever run.  i.e., is there any value to it, when the necessity to already be logging is being handled in each and every then already, guaranteeing that we WONT be missing ANYTHING')
            }
        }
    );
});

有错吗? 或者它是否有某种用途,即使我仍然在所有父链式 then-able 中对.then(resolve, reject)方法的所有用法使用错误/拒绝处理程序?

编辑:我希望更好的代码示例。我想我可能仍在命名中使用某种反模式,我rejectMessage例如,它是 jqXhr 对象,对吗?

所以也许我应该准确地命名它们或什么?即 jqXhr ? 顺便说一句,我喜欢在每个then()内部当场拒绝它的原因,如果有错误,是因为这样我就可以大量记录每个单独的呼叫,如果那里有具体问题,这样我就不必跟踪任何东西。微日志记录,因为我可以。

承诺正在帮助以这种方式打开调试世界。

这是我尝试过的三个例子。我更喜欢方法1和方法2,我绝不会回到方法3,这是我在应许之地开始的地方。

//method 1
app.rsvpAjax = function (){
    var async,
        promise = new window.RSVP.Promise(function(resolve, reject){
            async = $.extend( true, {},app.ajax, {
                success: function(returnData) {
                    resolve(returnData);
                },
                error: function(jqXhr, textStatus, errorThrown){
                    console.log('async error');
                    console.log({jqXhr:  jqXhr, textStatus: textStatus, errorThrown: errorThrown});
                    reject({ jqXhr: jqXhr, textStatus: textStatus, errorThrown: errorThrown}); //source of promise catch data believe
                }
            });
            $.ajax(async); //make the call using jquery's ajax, passing it our reconstructed object, each and every time
        });
    return promise;
};
app.callAPI = function () {
    var promise =app.rsvpAjax();
    if ( !app.ajax.url ) {
        console.log("need ajax url");
        promise.reject(); //throw (reject now)
    }
    return promise;
};
//method 2
app.ajaxPromise = function(){
    var  promise,  url = app.ajax.url;
    var coreObj = { //our XMLHttpRequestwrapper object
        ajax : function (method, url, args) {  // Method that performs the ajax request
            promise = window.RSVP.Promise( function (resolve, reject) {    // Creating a promise
                var client = new XMLHttpRequest(),  // Instantiates the XMLHttpRequest
                    uri = url;
                uri = url;
                if (args && (method === 'POST' || method === 'PUT')) {
                    uri += '?';
                    var argcount = 0;
                    for (var key in args) {
                        if (args.hasOwnProperty(key)) {
                            if (argcount++) {
                                uri += '&';
                            }
                            uri += encodeURIComponent(key) + '=' + encodeURIComponent(args[key]);
                        }
                    }
                }
                client.open(method, uri);
                client.send();
                client.onload = function () {
                    if (this.status == 200) {
                        resolve(this.response);   // Performs the function "resolve" when this.status is equal to 200
                    }
                    else {
                        reject(this.statusText); // Performs the function "reject" when this.status is different than 200
                    }
                };
                client.onerror = function () {
                    reject(this.statusText);
                };
            });
            return promise;   // Return the promise
        }
    };
    // Adapter pattern
    return {
        'get' : function(args) {
            return coreObj.ajax('GET', url, args);
        },
        'post' : function(args) {
            return coreObj.ajax('POST', url, args);
        },
        'put' : function(args) {
            return coreObj.ajax('PUT', url, args);
        },
        'delete' : function(args) {
            return coreObj.ajax('DELETE', url, args);
        }
    };
};
app.callAPI = function () {
    var async, callback;
    async =app.ajaxPromise() ; //app.ajaxPromise() is what creates the RSVP PROMISE HERE<
    if(app.ajax.type === 'GET'){async = async.get();}
    else if(app.ajax.type === 'POST') {async = async.post();}
    else if(app.ajax.type === 'PUT'){async = async.put();}
    else if(app.ajax.type === 'DELETE'){ async = async.delete();}
    callback = {
        success: function (data) {
            return JSON.parse(data);
        },
        error: function (reason) {
            console.log('something went wrong here');
            console.log(reason);
        }
    };
    async = async.then(callback.success)
        .catch(callback.error);
    return async;
};
//method 3 using old school jquery deferreds
app.callAPI = function () {
    //use $.Deferred instead of RSVP
    async = $.ajax( app.ajax) //run the ajax call now
        .then(
        function (asyncData) { //call has been completed, do something now
            return asyncData;  //modify data if needed, then return, sweet success
        },
        function(rejectMessage) {  //call failed miserably, log this thing
            console.log('Unexpected error inside the callApi.  There was a fail in the $.Deferred ajax call');
            return rejectMessage;
        }
    );
    return async;
};

我还在某个地方运行它onready作为另一个备份。

window.RSVP.on('error', function(error) {
    window.console.assert(false, error);
    var response;
    if(error.jqXhr){
        response = error.jqXhr;
    } else {
        //response = error;
        response = 'is this working yet?';
    }
    console.log('rsvp_on_error_report')
    console.log(response);
});

编辑错误示例

//one weird error I can't understand, an empty string("")?
{
  "jqXhr": {
    "responseText": {
      "readyState": 0,
      "responseText": "",
      "status": 0,
      "statusText": "error"
    },
    "statusText": "error",
    "status": 0
  },
  "textStatus": "error",
  "errorThrown": "'"'""
}
//another wierd one, but this one comes from a different stream,  the RSVP.on('error') function
{
  "readyState": 0,
  "responseText": "",
  "status": 0,
  "statusText": "error"
}

我把渔获放在最后

这是他们的典型位置 - 你处理链中某处发生的所有错误。重要的是不要忘记处理错误,最后有一个包罗万象的做法是推荐的做法。

即使我在所有.then(…)调用中使用onreject处理程序?

这有点奇怪。通常所有错误都在一个中心位置(最后是catch)处理,但当然,如果你愿意,你可以在任何地方处理它们,然后继续使用链。

只要确保了解thencatch中的onreject处理程序之间的区别,您就可以自由使用它们。尽管如此,建议最终catch来捕获then回调本身中的错误。

它们至少在一个特定实例中返回空对象。

然后承诺搞砸了——它永远不应该无缘无故地拒绝。似乎是由

if ( !app.ajax.url ) {
    console.log("need ajax url");
    promise.reject();
}

在你的代码中,这应该是

if (!app.ajax.url)
    return Promise.reject("need ajax url");
对于

任何未知的事情都需要捕获吗?

没有。问题在于,catch通常是包罗万象的,甚至会捕获意外的异常。因此,如果您可以区分它们,您会如何处理意想不到的?

通常,您会为它们设置某种全局未处理的拒绝处理程序,这样您就不必确保在每个承诺链结束时手动处理它们。

我认为一般问题应该在没有示例的情况下得到一个简单的答案。

迂腐的技术答案是"否",因为.catch(e)等同于.then(null, e)

但是

(这是一个很大的"但是"),除非您实际传入null,否则您将传入在运行时可能会失败的内容(例如编码错误),并且您需要后续catch来捕获它,因为同级拒绝处理程序在设计上不会捕获它:

.then(onSuccess, onFailure); // onFailure wont catch onSuccess failing!!

如果这是链条的尾巴,那么onSuccess中的错误(甚至是编码)就会永远被吞噬。所以不要那样做。

所以真正的答案是肯定的,除非你要返回链,在这种情况下没有。

所有链都应该终止,

但是如果你的代码只是调用方将在调用返回后添加到的较大链的一部分,那么由调用方正确终止它(除非你的函数设计为永远不会失败)。

我遵循的规则是:所有链都必须返回或终止(带有catch)。

如果我没记错的话,当你的承诺被拒绝时,catch会触发。由于附加了失败回调,因此除非您在失败或成功回调中调用拒绝函数,否则不会触发 catch。换句话说,catch 块正在捕获 then 方法中的拒绝。