如何“嵌套”javascript承诺?

xrfang

我编写了一个函数来使用fetch捕获非 200 个结果

 1 function $get(url, callback) {
 2  fetch(url, {credentials: "same-origin"})
 3    .then(resp => {
 4      if (!resp.ok) {
 5        resp.text().then((mesg) => {
 6          throw {"stat": resp.status, "mesg": mesg.trim()}
 7        })
 8        return resp.text()
 9      } 
10      return resp.json() 
11    })
12    .then(data => callback({"stat": 200, "data": data}))
13    .catch(error => callback(error))
14}

我在第 9 行出错:

ERROR: TypeError: Failed to execute 'text' on 'Response': body stream already read

我必须编写第 5~7 行所示代码的原因是,如果我写:

if (!resp.ok) {
  throw {"stat": resp.status, "mesg": resp.statusText}
return resp.json()

我会收到类似的错误消息{"stat": 403, "mesg": "Forbidden"},而我想要的是:{"stat": 403, "mesg": "invalid user name or password"}

在服务器端,我的 go 程序将生成非 200 回复,如下所示:

> GET /api/login?u=asdf&p=asdf HTTP/1.1
> Host: localhost:7887
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 403 Forbidden
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Sat, 17 Jul 2021 11:53:16 GMT
< Content-Length: 25
< 
invalid username or password

即 go 库不修改 http 状态文本,而是将错误消息放在body 中,这可能是 http 标准规定的(例如,状态文本不能更改)。

所以,我的问题是,要么:

  • 如何在不使用承诺的情况下阅读非 200 回复的正文?
  • 或者,如何在出现错误时回复“空”承诺,以防止再次读取流?

=== 编辑 ===

以下代码可以正常工作,但是,正如注释所指出的那样,它似乎使用了“反”模式:

function $get(url, callback) {
  fetch(url, {credentials: "same-origin"})
    .then(resp => {
      if (!resp.ok) {
        resp.text().then((mesg) => {
          callback({"stat": resp.status, "mesg": mesg.trim()})
        })
        return new Promise(function(_, _) {}) 
      } 
      return resp.json()
    })
    .then(data => callback({"stat": 200, "data": data}))
    .catch(error => { console.log(`GET ${url}\nERROR: ${error}`) })
}

然而,这母鹿工作:

function $get(url, callback) {
  fetch(url, {credentials: "same-origin"})
    .then(resp => {
      if (!resp.ok) {
        resp.text().then((mesg) => {
          throw `{"stat": resp.status, "mesg": mesg.trim()}`
        }) 
      } 
      return resp.json()
    })
    .then(data => callback({"stat": 200, "data": data}))
    .catch(error => { console.log(`GET ${url}\nERROR: ${error}`) })
}

throw会产生这个错误,而不是把控制权交给catch下面:

127.0.0.1/:1 Uncaught (in promise) {"stat": resp.status, "mesg": mesg.trim()}
保尔·克鲁伊特

考虑到您正在使用,fetch您还可以使用async/await并执行以下操作。

async function $get(url, callback) {
  try {
    const resp = await fetch(url, {credentials: "same-origin"});
    
    if (!resp.ok) {
      // this will end up in the catch statement below
      throw({ stat: resp.status, mesg: (await resp.text()).trim());
    }
    
    callback({ stat: 200, data: await resp.json() });
  } catch(error) {
    callback(error);
  }
}

我不明白你为什么要使用callback函数 :) 那些都是 1999


为了解释您的错误,您resp.text()在出现错误时调用了两次。为了防止这种情况,您应该立即返回从第一次resp.text()调用链接的承诺这也会抛出错误并在没有到达连续then()语句的情况下在 catch 块中结束

function $get(url, callback) {
 fetch(url, {credentials: "same-origin"})
   .then(resp => {
     if (!resp.ok) {
       return resp.text().then((mesg) => {
//     ^^^^^^
         throw {stat: resp.status, error: mesg.trim()}
       });
     } 
     return resp.json() ;
   })
   .then(data => callback({stat: 200, data }))
   .catch(error => callback(error))
}

$get不使用回调的“正确”函数:

function $get(url) {
  return fetch(url, {credentials: "same-origin"}).then(async (resp) => {
    const stat = resp.status;

    if (!resp.ok) {
      throw({ stat, error: (await resp.text()).trim() });
    }

    return { stat, data: await resp.json() };
  });
}

您可以像这样消费:

$get('https://example.com')
  .then(({ stat, data }) => {

  })
  .catch({ stat, error}) => {

  })

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章