我想创建一个执行异步操作并返回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 回答
正如您明确提到的那样,
$.ajax
仅针对您的其他一个案例失败,因此您可以使用一些自定义验证轻松处理该案例 . 您可以将解析包含在try catch
块中这听起来像deferred antipattern . 不要包装任何已经使用承诺的东西 .
是:
另见Throwing an Error in jQuery's Deferred object .
实际上,您的原始代码在任何合理的承诺实现中都有效,其中异常会被隐含地拒绝 . 这只是jQuery's fail . 你可能只想dodge jQuery's then implementation .
正如已经描述的那样,jQuery 1.x和2.x承诺不符合promise规范,并且那些版本中的
.then()
处理程序不是"throw-safe" . 有了正确的承诺,异常将自动变为拒绝 .Bergi已经展示了如何手动捕获异常并手动将其转换为jQuery中的拒绝 . 但是,您也可以将jQuery承诺转换为真正的承诺,然后免费获得该抛出安全行为 . 这是一种方法:
或者,或许甚至更好,制作一个新版本的
$.ajax()
,它返回一个标准的承诺,然后使用它:这两个选项都意味着你的
fetch()
函数现在返回一个标准的promise,而不是一个jQuery的promise,所以它不会像_949965那样拥有一些jQuery特定的东西,但它会有符合标准的promise承诺行为 .