我想将下面的callEndPointWrapper转换为返回Promise而不是回调。
我已经使用以下代码进行了测试,但是在Promise上等待callEndpointWrapper()的请求已超时。
我在下面缺少任何东西吗?
(在调试时,我在等待Promise时看到请求在下面的代码行中超时:return (function callEndpoint(callback): any {
打回来:
function callEndPointWrapper(): any {
return function callEndpoint(callback) {
try {
// gRPC call
client[methodName](req, options, callback);
}
catch (err) {
callback(err);
}
};
}
const result = yield callEndpointWrapper();
// I get the correct result from callback above (both on success or error)
诺言:
function callEndPointWrapper(): Promise<any> {
return new Promise( (resolve, reject) => {
return (function callEndpoint(callback): any {
try {
// gRPC call
resolve(client[methodName](req, options, callback));
} catch (err) {
reject(callback(err));
}
});
});
const result = await callEndpointWrapper();
// Above request times out.
最佳答案
callEndPointWrapper
的期望结果似乎是一个函数(callEndPoint
),它执行一些异步工作,您可以进一步调用该异步工作来执行某些操作。
在回调方法中,您正在生成此callEndPoint
函数。
----> callEndPointWrapper
返回执行异步工作的callEndPoint
。
另一方面,在基于诺言的方法中,您尝试产生callEndPoint
的结果,而不是返回callEndPoint
本身。实际上,在callEndPoint
构造函数中永远不会调用Promise
。
----> callEndPointWrapper
返回一个永不解决的承诺,并在内部创建callEndPoint
函数,该函数不执行任何操作,因为它从未被调用。
重要的是要注意,对callEndPointWrapper
的单个调用不是异步的。实际的异步部分(假设client
方法是异步的)发生在callEndpoint
中,因此基于回调的方法的异步调用将类似于:
callEndPointWrapper()(
function callback(responseFromEndpoint) {
// ...
}
)
// or something like
let caller = callEndPointWrapper();
caller(function callback(responseFromEndpoint) {
// ...
});
因此,基于诺言的方法也将需要两个调用:
await callEndPointWrapper()(); // call a wrapper which returns a function which returns a promise
以下是功能上等效(就产生的结果而言)的基于promise的回调代码:
function callEndPointWrapper(): any {
return function callEndpoint() {
return new Promise((resolve, reject) => {
try {
client[methodName](req, options, (err, result) => {
if (err) return reject(err);
resolve(result);
});
} catch (err) {
// Note: this rejection will only happen on any sync errors
// with the above code, such as trying to invoke a non-existing
// method on the client. This type of error is a programmer error
// rather than an operational error in the system so you should
// consider if such errors should even by caught by your code.
reject(err);
}
});
};
}
但是,这引出了一个问题,即如果您没有传递任何配置选项以使
callEndpoint
函数的结尾可用,那么完全具有包装器功能有什么意义呢?根据您的示例用法,您只需要
callEndpoint
方法。想到您可能正在使用类似
co
之类的东西,它允许您使用yield
函数(thunk)并使用回调在内部调用它们。所以当你这样做
yield callEndpointWrapper()
你实际上是在打电话
yield function callEndpoint(callback) {
// ...
}
然后
co
为您做一些魔术。这是deprecated by
co
的模式,总体上不建议使用。更不用说这是非常令人困惑的(和丑陋的恕我直言)行为,需要了解特定的库。要将诺言与
co
一起使用,则不需要包装函数。只是yield
或await
调用callEndPoint
的结果(与我上面的promise示例中的结果相同),这将是一个promise。yield callEndPoint()
// or
await callEndPoint()