将回调转换为Promise

时间:2017-11-10 16:06:25

标签: javascript node.js callback promise

我想转换下面的callEndPointWrapper来返回Promise而不是回调。 我已经使用下面的代码进行了测试,但是等待Promise for 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.

1 个答案:

答案 0 :(得分:1)

callEndPointWrapper的期望结果似乎是一个函数(callEndPoint),它执行一些异步工作,您可以进一步调用它来执行某些操作。

在回调方法中,您正在生成此callEndPoint函数。

----&GT; callEndPointWrapper返回执行异步工作的callEndPoint

另一方面,在基于承诺的方法中,您试图生成callEndPoint的结果而不是返回callEndPoint本身。实际上,callEndPoint永远不会在Promise构造函数中调用callEndPointWrapper

----&GT; callEndPoint返回一个永不解析的promise,并在内部创建不执行任何操作的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

由此可见,基于承诺的方法也需要两次调用:

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函数的闭包中可用,那么这就产生了一个问题:如何设置包装函数呢?

根据您的示例用法,您只需要yield方法。

我想到你可能正在使用类似co的东西,它允许你yield callEndpointWrapper() 函数(thunks)并在内部通过回调调用它们。

所以当你这样做时

yield function callEndpoint(callback) {
  // ...
}

你实际上是在打电话

co

然后co为你做了一些魔术。

这是一种deprecated by co的模式,总体上不明智。更不用说它需要知道特定的库,这是非常混乱(和丑陋的恕我直言)行为。

要使用yield的承诺,您不需要包装函数。只需awaitcallEndPoint调用yield callEndPoint() // or await callEndPoint() 的结果(与我上面的承诺示例相同),这将是一个承诺。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ScrollView
            android:id="@+id/shoppingDetailsScrollView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="#aabbcc"
            android:fillViewport="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">


            <android.support.constraint.ConstraintLayout
                android:id="@+id/contentContainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="20dp"
                android:background="@color/place_holder_color">

            </android.support.constraint.ConstraintLayout>
        </ScrollView>

    </android.support.constraint.ConstraintLayout>