进行GraphQL查询时,查询失败,Apollo通过具有数据对象和错误对象来解决此问题。
当发生异步错误时,我们可以使用一个数据对象和一个错误对象获得相同的功能。但是,这次我们也得到了UnhandledPromiseRejectionWarning
,其中包含有关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.
的信息。
因此,我们显然需要解决此问题,但是我们希望异步函数将错误一直传递到Apollo。我们是否需要尝试...捕获所有功能,然后将错误进一步传递到树上?来自C#的一个例外是,如果从未捕获到一个异常,它会一直上升到顶端。要告诉Apollo GraphQL,一个(或多个)叶子无法从数据库中检索数据听起来很繁琐。
是否有更好的方法来解决此问题,或者有什么办法告诉javascript / node一个未捕获的错误应进一步传递到调用树,直到被捕获?
答案 0 :(得分:1)
如果您正确地兑现了承诺,您将永远不会看到此警告,并且GraphQL会捕获所有错误。假设我们有这两个返回Promise的函数,后者总是拒绝:
async function doSomething() {
return
}
async function alwaysReject() {
return Promise.reject(new Error('Oh no!'))
}
首先,给出一些正确的例子:
someField: async () => {
await alwaysReject()
await doSomething()
},
// Or without async/await syntax
someField: () => {
return alwaysReject()
.then(() => {
return doSomething()
})
// or...
return alwaysReject().then(doSomething)
},
在所有这些情况下,您将在errors
数组中看到错误,并且在控制台中没有警告。我们可以颠倒函数的顺序(首先调用doSomething
),情况仍然如此。
现在,让我们破坏代码:
someField: async () => {
alwaysReject()
await doSomething()
},
someField: () => {
alwaysReject() // <-- Note the missing return
.then(() => {
return doSomething()
})
},
在这些示例中,我们关闭了该函数,但我们没有等待返回的Promise。这意味着我们的解析器将继续执行。如果未解决的Promise解决了,我们将无法处理其结果-如果它拒绝了,我们将无法对错误进行处理(警告未表明,该错误未得到处理)。
通常,您应始终确保正确地链接了Promises(承诺),如上所示。通过async / await语法,这非常容易实现,因为如果没有它,则很容易错过return
。
副作用如何?
可能有一些函数返回您要运行的Promise,但不想暂停您的解析程序的执行。 Promise解决还是返回与您的解决程序返回的内容无关,您只需要运行它即可。在这些情况下,我们只需要catch
来处理被拒绝的承诺:
someField: async () => {
alwaysReject()
.catch((error) => {
// Do something with the error
})
await doSomething()
},
在这里,我们调用alwaysReject
,执行继续到doSomething
。如果alwaysReject
最终拒绝,错误将被捕获,并且控制台中不会显示任何警告。
注意:这些“副作用”没有被等待,这意味着GraphQL执行将继续,并且在它们仍在运行时可以很好地完成。没办法在GraphQL响应(即errors
数组)中包含来自副作用的错误,充其量您只能记录下来。如果您希望在响应中显示某个Promise的拒绝原因,则需要在解析器中等待它,而不是将其视为副作用。
关于try / catch and catch的最后一句话
在处理Promises时,我们经常会在函数调用后看到错误,例如:
try {
await doSomething()
} catch (error) {
// handle error
}
return doSomething.catch((error) => {
//handle error
})
这在同步上下文中非常重要(例如,在使用express构建REST api时)。未能兑现被拒绝的承诺将导致熟悉的UnhandledPromiseRejectionWarning
。但是,由于GraphQL的执行层有效地充当了一个巨大的try / catch,因此只要正确地链接/等待了Promises,就没有必要捕获错误。除非A)您正在处理已经说明的副作用,或者B)要防止错误冒泡,否则这是正确的:
try {
// execution halts because we await
await alwaysReject()
catch (error) {
// error is caught, so execution will continue (unless I throw the error)
// because the resolver itself doesn't reject, the error won't be bubbled up
}
await doSomething()