【问题标题】:Proper mindset for use of promises?使用承诺的正确心态?
【发布时间】:2017-09-23 19:04:55
【问题描述】:

我最近才看到 promises(JS 不是我的强项),我不确定这样做的正确方法是什么。 Promise 应该防止代码向右漂移,但是当我最终得到一些复杂的逻辑时,无论如何我最终嵌套得太深了,所以我确信我做错了。

如果我将成功和失败都作为 json 值返回,并且我也想处理格式错误的 json,我会立即考虑执行以下操作:

fetch('json').then(function (result) {
    return result.json();
}).catch(function (result) {
    console.error("Json parse failed!");
    console.error(result.text);
}).then(function (wat) {
    // if (!result.ok) { throw...
}).catch(function (wat) {
    // Catch http error codes and log the json.errormessage
});

当然,这行不通。这是典型的同步代码。但这是首先想到的。我能看到的问题:

  • 如何同时获得响应和 json 输出?
  • 如何获得错误和成功的单独控制流?
  • 如何捕获两种响应类型的 json 解析错误?

我最好的尝试是嵌套到我可能会使用回调的地步,但它最终不起作用,因为我仍然没有解决上述任何问题:

fetch('json').then(function (response) {
    if (!response.ok) {
        throw response;
    }
}).then(
    function (response) {
        response.json().then(function (data) {
            console.log(data);
        });
    },
    function (response) {
        response.json().then(function (data) {
            console.error(data.errormessage);
        });
    }
).catch(function () {
    console.error("Json parse failed!");
    // Where's my response????
});

执行此操作的“正确”方法是什么? (或者至少错误更少)

【问题讨论】:

  • 您的大部分“嵌套”只是奇怪的格式。为什么将函数表达式中的两个传递给then 时缩进,而只传递一个时却不缩进?
  • 是的,复杂的逻辑通常涉及嵌套(withpromises 或没有),这很好。只需确保always return the inner promises 保持一个奇异的结果值。

标签: javascript promise


【解决方案1】:

如果您无论如何都想调用response.json()(用于成功和失败的响应)并且想将response 一起使用将响应数据。使用Promise.all

fetch('json')
  .then(response => Promise.all([response, response.json()]))
  .then(([response, data]) => {
    if (!response.ok) {
      console.error(data.errormessage);
    } else {
      console.log(data);
    }
  })
  .catch(err => {
    if (/* if http error */) {
      console.error('Http error');
    } else if (/* if json parse error */) 
      console.error('Json parse failed');
    } else {
      console.error('Unknown error: ' + err);
    }
  });

【讨论】:

  • 这行得通。如果我想在 if 的两边用不同的逻辑进行更多的提取,会发生什么?有没有办法把它链起来还是我就开始嵌套?
  • 如果您需要将上一个调用的结果传递给下一个then,请再次使用Promise.all(使用上一个结果和新的 fetch 调用)。如果不需要上一个结果,只需调用 fetch。
  • 这里有一个微妙的错误:如果 fetch 拒绝了承诺,这将错误地记录“Json parse failed!”。
  • 您需要在catch 回调中检查err 对象(typename)以识别错误并打印正确的消息。
  • @alexmac 你应该编辑你的代码来解决这个问题。就目前而言,这是一个错误。
【解决方案2】:

你不应该在 Promises 中使用异常来控制流,就像在不使用 Promises 时一样。这就是为什么 fetch 本身不仅仅拒绝 200 以外的状态码的承诺。

这是一个建议,但答案必然取决于您的具体需求。

fetch('json').then(function (response) {
    if (!response.ok) {
        response.json().then(function (data) {
            console.error(data.errorMessage);
        });
        return ...;
    }

    return response.json().catch(function () {
        console.error("Json parse failed!");
        return ...;
    });
}).catch(function (e) {
    console.error(e);
    return ...;
});

【讨论】:

  • 这不就等同于回调吗?如果我想根据 json 内容发送另一个请求,我必须在 then 内这样做,并且嵌套会变得更糟吗?
  • 请注意,您必须 return response.json().then(…) 承诺,之后返回其他内容将不起作用。
  • @JV 如果你开始分支,无论如何你都会得到嵌套。 Promise 将减少顺序异步调用的嵌套,但如果您的逻辑不是顺序的,则无法执行任何操作。
  • @Bergi 如果您想返回其他内容(例如默认值),它可以正常工作。返回嵌套的 Promise 是行不通的,因为它也不会返回任何东西(当然它可以,如果你需要的话)。
  • 是的,通常您会希望将错误消息用作结果值,或者作为拒绝进一步处理。在您的情况下,如果您只是想 console.log 它,那可能没问题,但是您还应该从该子链中出现 .catch 错误(如果 .json() 无法解析响应,则抛出)。
猜你喜欢
  • 2013-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-23
  • 2023-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多