如何"nest"javascript承诺?
How to "nest" javascript promise?
我用 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 标准强制要求的(例如,状态文本不能更改)。
所以,我的问题是:
- 如何在不使用 promise 的情况下读取非 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()
。为防止这种情况,您应该立即 return 从第一个 resp.text()
调用链接的承诺。这也将抛出错误并最终进入 catch 块,而没有到达连续的 then()
语句:
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}) => {
})
只是 return 被拒绝的承诺,你就可以开始了
1 function $get(url, callback) {
2 fetch(url, {credentials: "same-origin"})
3 .then(resp => {
4 if (!resp.ok) {
5 return resp.text().then((mesg) => {
6 throw {"stat": resp.status, "mesg": mesg.trim()}
7 })
9 }
10 return resp.json()
11 })
12 .then(data => callback({"stat": 200, "data": data}))
13 .catch(error => callback(error))
14}
我用 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 标准强制要求的(例如,状态文本不能更改)。
所以,我的问题是:
- 如何在不使用 promise 的情况下读取非 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()
。为防止这种情况,您应该立即 return 从第一个 resp.text()
调用链接的承诺。这也将抛出错误并最终进入 catch 块,而没有到达连续的 then()
语句:
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}) => {
})
只是 return 被拒绝的承诺,你就可以开始了
1 function $get(url, callback) {
2 fetch(url, {credentials: "same-origin"})
3 .then(resp => {
4 if (!resp.ok) {
5 return resp.text().then((mesg) => {
6 throw {"stat": resp.status, "mesg": mesg.trim()}
7 })
9 }
10 return resp.json()
11 })
12 .then(data => callback({"stat": 200, "data": data}))
13 .catch(error => callback(error))
14}