首页 文章

承诺错误/异常处理设计

提问于
浏览
4

我想创建一个执行异步操作并返回promise的函数 . 行动是:

  • 通过AJAX下载外部内容

  • 如果无法下载内容(例如无效的网址) - > reject

  • 如果内容下载成功,但我无法解析 - > reject

  • 否则(内容已成功下载并解析) - > resolve

我现在得到的代码非常明确:

function fetch(hash){
  return $.ajax({
    method: "GET",
    url: baseURL + "/gists/" + hash
  }).then(function(response) {
    return JSON.parse(response.files['schema.json'].content);
  });
}

它只是一个从github gist获取数据的jQuery AJAX调用 . 目前:

  • 当AJAX无法解决时 - >承诺被拒绝 - 好的

  • 当AJAX解析并且内容被正确解析时 - > promise得到解决 - 好的

  • however ,如果AJAX已解决,但内容无效, JSON.parse 行会抛出错误并且承诺 doesn't get rejected 并且它应该 - 失败

The question is - what is the right design to do that? 我可以用Deferred包装整个东西并手动处理它,但我认为可能有一个更简单的解决方案 . 我应该试试吗?或者是其他东西?

3 回答

  • 0

    正如您明确提到的那样, $.ajax 仅针对您的其他一个案例失败,因此您可以使用一些自定义验证轻松处理该案例 . 您可以将解析包含在 try catch 块中

  • 2

    我可以用Deferred包装整个东西并手动处理它

    这听起来像deferred antipattern . 不要包装任何已经使用承诺的东西 .

    我认为可能有一个更简单的解决方案 . 我应该试试吗?

    是:

    .then(function(response) {
      try {
        return JSON.parse(response.files['schema.json'].content);
      } catch (e) {
        return $.Deferred().reject(e);
      }
    })
    

    另见Throwing an Error in jQuery's Deferred object .

    还是其他什么?

    实际上,您的原始代码在任何合理的承诺实现中都有效,其中异常会被隐含地拒绝 . 这只是jQuery's fail . 你可能只想dodge jQuery's then implementation .

  • 1

    正如已经描述的那样,jQuery 1.x和2.x承诺不符合promise规范,并且那些版本中的 .then() 处理程序不是"throw-safe" . 有了正确的承诺,异常将自动变为拒绝 .

    Bergi已经展示了如何手动捕获异常并手动将其转换为jQuery中的拒绝 . 但是,您也可以将jQuery承诺转换为真正的承诺,然后免费获得该抛出安全行为 . 这是一种方法:

    function fetch(hash){
      return Promise.resolve($.ajax({
        method: "GET",
        url: baseURL + "/gists/" + hash
      })).then(function(response) {
        return JSON.parse(response.files['schema.json'].content);
      });
    }
    

    或者,或许甚至更好,制作一个新版本的 $.ajax() ,它返回一个标准的承诺,然后使用它:

    $.ajaxStd = function() {
        return Promise.resolve($.ajax.apply($, arguments));
    }
    
    function fetch(hash){
      return $.ajaxStd({
        method: "GET",
        url: baseURL + "/gists/" + hash
      }).then(function(response) {
        return JSON.parse(response.files['schema.json'].content);
      });
    }
    

    这两个选项都意味着你的 fetch() 函数现在返回一个标准的promise,而不是一个jQuery的promise,所以它不会像_949965那样拥有一些jQuery特定的东西,但它会有符合标准的promise承诺行为 .

相关问题