为什么在 catch 块内的代码完成之前评估 then 块内的代码
Why is code inside then block being evaluated before the code inside catch block completes
代码如下:
function f1(id) {
return new Promise((resolve, reject) => {
if (id === 123132) {
resolve([{id:1,name:"John"}, {id:10, name:"Chris"}])
} else {
reject(new Error("f1 fails - can't find info for id"))
}
})
}
function f2(gender) {
return new Promise((resolve, reject) => {
if (gender === "FEMALE") {
resolve([{id:6, name:"Stacy"}, {id:1, name:"John"}, {id:13, name:"Veronica"}])
} else {
reject(new Error("f2 Fails"))
}
})
}
function Test(User, N){
return new Promise((resolve, reject)=>{
f1(User.id).catch(err=>{
console.log(err.message)
//this api returns an error, so call the other one
f2(User.gender).catch(err=>{
console.log(err.message)
reject(new Error("Both api calls have failed"))
}).then(res=>{
if (res.length<N){
reject(new Error("Not Enough Data..."))
} else {
console.log("We are here..")
console.log(res)
resolve(res.slice(0,N).map(item=>item.name))
}
})
})
.then(res1=>{
console.log("We should not be here but we are...")
console.log(res1)
if (res1.length<N){
f2(User.gender).catch(err=>{
console.log(err.message)
// reject(new Error("Not Enough Data"))
throw new Error("Not Enough Data")
}).then(res2=>{
res3 = filterDups2(res1, res2)
res3.length>=N ? resolve(res3.slice(0,N).map(item=>item.name)) :
reject(new Error("Not Enough Data"))
})
} else {
console.log("Why are we not here...")
resolve(res1.slice(0,N).map(item=>item.name))
}
})
})
}
function filterDups2(list1, list2){
jointRes = [...list1, ...list2]
ans = Array.from(new Set(jointRes.map(item=>JSON.stringify(item)))).map(item=>JSON.parse(item))
return ans
}
let user = { id: 123, gender: "FEMALE" }
let result = Test(user, 2)
result.then(res=> console.log(res)).catch(err=> {
console.log("Inside result...")
console.log(err.message)
})
这是控制台上的输出:
f1 fails - can't find info for id
We should not be here but we are...
undefined
We are here..
[
{ id: 6, name: 'Stacy' },
{ id: 1, name: 'John' },
{ id: 13, name: 'Veronica' }
]
[ 'Stacy', 'John' ]
(node:2968) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'length' of undefined
at /Users/daanishraj/Desktop/Front-End-Work/WDB-Feb-2021/JavaScript/Practice/interviews/zalando/forWhosebug.js:50:20
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2968) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:2968) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
我不明白为什么我们在控制台上有以下两个东西
We should not be here but we are...
undefined
出现在这些输出之前:
We are here..
[
{ id: 6, name: 'Stacy' },
{ id: 1, name: 'John' },
{ id: 13, name: 'Veronica' }
]
[ 'Stacy', 'John' ]
我知道因为最外层的 catch 块,即 f1(U.id).catch() 已解析,这将使我们进入最外层的 then 块,即 f1(U.id).then ().但是这些输出的顺序表明我们在解析 catch 块之前进入 then 块。
- 为什么会这样?
- 既然我们确实进入了 then 块,一旦 res1 被认为是
undefined
,为什么控件不移动到我们将输出 Why are we not here...
的 then 块的底部?
总的来说,如果您能阐明这里的执行顺序,那就太好了!
Why is this the case?
因为您没有指示承诺链等待来自 catch
处理程序的异步结果。为此,您需要 return
那里的承诺。
进入 then
处理程序不会发生“ 在 catch 块被解析之前 ”,catch
处理程序确实已经执行并且 return undefined
- 这就是承诺链的延续。
Why doesn't the control move to the bottom of the then block where we would output "Why are we not here..."?
因为在记录 undefined
之后,您访问 res1.length
,这会导致异常 TypeError: Cannot read property 'length' of undefined
。这拒绝了未在任何地方处理的承诺,导致警告。
现在进入真正的问题:如何正确地做到这一点?您应该避免使用 Promise
constructor antipattern! The .then()
and .catch()
calls already return a promise for the result of the handler, which you can and should use - no need to manually resolve
or reject
a promise, and no unhandled promise rejections because some inner promise is rejected but you fail to propagate this failure outside (notice the "Inside result..." handler should have been called when res1.length
errored). Also I recommend to use .then(…, …)
instead of .then(…).catch(…)
(或 .catch(…).then(…)
)进行条件 success/error 处理。
function Test(User, N) {
return f1(User.id).then(res1 => {
// ^^^^^^
if (res1.length < N) {
return f2(User.gender).then(res2 => {
// ^^^^^^
const res3 = filterDups2(res1, res2)
if (res3.length >= N)
return res3.slice(0,N).map(item => item.name)
// ^^^^^^
else
throw new Error("Not Enough Data")
// ^^^^^
}, err => {
console.log(err.message)
throw new Error("Not Enough Data")
// ^^^^^
})
} else {
return res1.slice(0,N).map(item => item.name)
// ^^^^^^
}
}, err => {
console.log(err.message)
return f2(User.gender).then(res => {
// ^^^^^^
if (res.length < N) {
throw new Error("Not Enough Data...")
// ^^^^^
} else {
return res.slice(0,N).map(item => item.name);
// ^^^^^^
}
}, err => {
console.log(err.message)
throw new Error("Both api calls have failed")
// ^^^^^
})
})
}
避免一些代码重复:
function Test(User, N) {
return f1(User.id).then(res1 => {
if (res1.length >= N) return res1;
return f2(User.gender).then(res2 => {
return filterDups2(res1, res2)
}, err => {
console.log(err.message)
return res1;
})
}, err => {
console.log(err.message)
return f2(User.gender).catch(err => {
console.log(err.message)
throw new Error("Both api calls have failed")
})
}).then(res => {
if (res.length >= N)
return res.slice(0,N).map(item => item.name)
else
throw new Error("Not Enough Data")
})
}
代码如下:
function f1(id) {
return new Promise((resolve, reject) => {
if (id === 123132) {
resolve([{id:1,name:"John"}, {id:10, name:"Chris"}])
} else {
reject(new Error("f1 fails - can't find info for id"))
}
})
}
function f2(gender) {
return new Promise((resolve, reject) => {
if (gender === "FEMALE") {
resolve([{id:6, name:"Stacy"}, {id:1, name:"John"}, {id:13, name:"Veronica"}])
} else {
reject(new Error("f2 Fails"))
}
})
}
function Test(User, N){
return new Promise((resolve, reject)=>{
f1(User.id).catch(err=>{
console.log(err.message)
//this api returns an error, so call the other one
f2(User.gender).catch(err=>{
console.log(err.message)
reject(new Error("Both api calls have failed"))
}).then(res=>{
if (res.length<N){
reject(new Error("Not Enough Data..."))
} else {
console.log("We are here..")
console.log(res)
resolve(res.slice(0,N).map(item=>item.name))
}
})
})
.then(res1=>{
console.log("We should not be here but we are...")
console.log(res1)
if (res1.length<N){
f2(User.gender).catch(err=>{
console.log(err.message)
// reject(new Error("Not Enough Data"))
throw new Error("Not Enough Data")
}).then(res2=>{
res3 = filterDups2(res1, res2)
res3.length>=N ? resolve(res3.slice(0,N).map(item=>item.name)) :
reject(new Error("Not Enough Data"))
})
} else {
console.log("Why are we not here...")
resolve(res1.slice(0,N).map(item=>item.name))
}
})
})
}
function filterDups2(list1, list2){
jointRes = [...list1, ...list2]
ans = Array.from(new Set(jointRes.map(item=>JSON.stringify(item)))).map(item=>JSON.parse(item))
return ans
}
let user = { id: 123, gender: "FEMALE" }
let result = Test(user, 2)
result.then(res=> console.log(res)).catch(err=> {
console.log("Inside result...")
console.log(err.message)
})
这是控制台上的输出:
f1 fails - can't find info for id
We should not be here but we are...
undefined
We are here..
[
{ id: 6, name: 'Stacy' },
{ id: 1, name: 'John' },
{ id: 13, name: 'Veronica' }
]
[ 'Stacy', 'John' ]
(node:2968) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'length' of undefined
at /Users/daanishraj/Desktop/Front-End-Work/WDB-Feb-2021/JavaScript/Practice/interviews/zalando/forWhosebug.js:50:20
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2968) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:2968) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
我不明白为什么我们在控制台上有以下两个东西
We should not be here but we are...
undefined
出现在这些输出之前:
We are here..
[
{ id: 6, name: 'Stacy' },
{ id: 1, name: 'John' },
{ id: 13, name: 'Veronica' }
]
[ 'Stacy', 'John' ]
我知道因为最外层的 catch 块,即 f1(U.id).catch() 已解析,这将使我们进入最外层的 then 块,即 f1(U.id).then ().但是这些输出的顺序表明我们在解析 catch 块之前进入 then 块。
- 为什么会这样?
- 既然我们确实进入了 then 块,一旦 res1 被认为是
undefined
,为什么控件不移动到我们将输出Why are we not here...
的 then 块的底部?
总的来说,如果您能阐明这里的执行顺序,那就太好了!
Why is this the case?
因为您没有指示承诺链等待来自 catch
处理程序的异步结果。为此,您需要 return
那里的承诺。
进入 then
处理程序不会发生“ 在 catch 块被解析之前 ”,catch
处理程序确实已经执行并且 return undefined
- 这就是承诺链的延续。
Why doesn't the control move to the bottom of the then block where we would output "Why are we not here..."?
因为在记录 undefined
之后,您访问 res1.length
,这会导致异常 TypeError: Cannot read property 'length' of undefined
。这拒绝了未在任何地方处理的承诺,导致警告。
现在进入真正的问题:如何正确地做到这一点?您应该避免使用 Promise
constructor antipattern! The .then()
and .catch()
calls already return a promise for the result of the handler, which you can and should use - no need to manually resolve
or reject
a promise, and no unhandled promise rejections because some inner promise is rejected but you fail to propagate this failure outside (notice the "Inside result..." handler should have been called when res1.length
errored). Also I recommend to use .then(…, …)
instead of .then(…).catch(…)
(或 .catch(…).then(…)
)进行条件 success/error 处理。
function Test(User, N) {
return f1(User.id).then(res1 => {
// ^^^^^^
if (res1.length < N) {
return f2(User.gender).then(res2 => {
// ^^^^^^
const res3 = filterDups2(res1, res2)
if (res3.length >= N)
return res3.slice(0,N).map(item => item.name)
// ^^^^^^
else
throw new Error("Not Enough Data")
// ^^^^^
}, err => {
console.log(err.message)
throw new Error("Not Enough Data")
// ^^^^^
})
} else {
return res1.slice(0,N).map(item => item.name)
// ^^^^^^
}
}, err => {
console.log(err.message)
return f2(User.gender).then(res => {
// ^^^^^^
if (res.length < N) {
throw new Error("Not Enough Data...")
// ^^^^^
} else {
return res.slice(0,N).map(item => item.name);
// ^^^^^^
}
}, err => {
console.log(err.message)
throw new Error("Both api calls have failed")
// ^^^^^
})
})
}
避免一些代码重复:
function Test(User, N) {
return f1(User.id).then(res1 => {
if (res1.length >= N) return res1;
return f2(User.gender).then(res2 => {
return filterDups2(res1, res2)
}, err => {
console.log(err.message)
return res1;
})
}, err => {
console.log(err.message)
return f2(User.gender).catch(err => {
console.log(err.message)
throw new Error("Both api calls have failed")
})
}).then(res => {
if (res.length >= N)
return res.slice(0,N).map(item => item.name)
else
throw new Error("Not Enough Data")
})
}