如何将不包含回调参数的函数转换为Promise函数?

3

我目前正在开发一个API /路由器,要将其集成到用户自己的Web服务器中。我的代码将执行所需的工作,但也允许用户实现自己的逻辑,如此片段:myApi.on('action', (err, result, req, res) => {/*user's logic here*/})

根据设计,如果用户决定覆盖默认行为并实现自己的逻辑,我的代码将不会结束响应。这是为了允许请求和响应流传到下一个中间件函数,如果用户希望的话。

我想要的控制流程是:

  1. 运行我的初始路由逻辑

  2. 运行用户自定义逻辑

  3. 如果响应尚未结束,则将控制权传递给下一个中间件函数

我的问题出现在当用户想要实现任何异步逻辑时。在将控制权传递给下一个中间件函数之前,我无法让用户的自定义逻辑得到结论。我认为这是因为我设置的接口。我希望用户尽可能少地处理繁琐的工作。这意味着我更喜欢不传递给用户类似于callback()next()函数的等效物,因为他们需要在其逻辑的每个端点调用它(由于我的路由器涉及许多不同的路由)。

我研究了一些 promise wrappers,例如 promisify-node,但它们似乎只能包装以回调作为最终参数的函数。我还考虑要求用户从其自定义实现中返回一个promise,但这与我不想要求繁琐/样板代码的愿望相矛盾。

是否有使用 promises 或其他结构的方法,可以解决这个异步问题,而不必让用户感到痛苦?


你如何定义一个请求已经结束? - Amit
@Amit,看起来我弄反了请求和响应。我会检查res.finished标签以确保响应已完成。 - TheKingOfTyrants
2个回答

2

不,如果一个函数没有回调函数的话,你就不能将其转化为Promise。这样的函数要么不是异步的,要么没有提供任何方法让你知道它什么时候完成 - 你就没办法了。

我的问题出现在当用户想要实现任何异步逻辑时。

如果用户想要实现异步操作,只需要求他传递返回Promise的函数即可。这样做对他来说可能会更方便,因为他必须使用Promise来处理异步操作 :-)

const myApi = {
    on(name, fn) {
        Promise.resolve(result) // or whenever you need to run the user logic
        .then(result => 
            fn(req, result) // or whatever you want to pass
        )
        .then(customresult => {
            res.write(customresult); // or whatever you want to do with its result
        });
    }
};

myApi.on('action', (req, result) => {
    // user's logic here
    // throw exceptions
    // return values
    // return promises for values
    // or whatever the user needs to do
})

0

如果我理解你的问题,你需要检查用户自定义函数返回的值。如果它是一个类似于promise的对象,那么你可以等待它解决后再继续执行。这相当于将一个next函数传递给用户自定义中间件。

在你的例子中,用户将像这样使用你的API:

myApi.on('action', (err, result, req, res) => {
  return myPromiseAwareAsyncFunction();
})

在你的代码中:

let userMiddleWare = lookupNextActionHandler();
let result = userMiddleWare(err, result, req, res);
// Wrap any value (promise or not) in a promise
Promise.resolve(result)
  .then(result => {
    // Move on to next middle ware
  })
  .catch(error => {
    console.error(error);
    process.exit(1); // Or what ever you use
                     // to end the middle ware chain.
  });

如果您希望同时提供Promise和next回调,您可以尝试以下方案:
let userMiddleWare = lookupNextActionHandler();
new Promise((resolve, reject) => {
  function next(err) {
    if (err) {
      reject(err);
    } else {
      resolve();
    }
  }
  let result = userMiddleWare(err, result, req, res, next);
  Promise.resolve(result).then(resolve).catch(reject);
})
.then(result => {
  // Move on to next middle ware
})
.catch(error => {
  console.error(error);
  process.exit(1); // Or what ever you use
                   // to end the middle ware chain.
});

由于 Promise 只能处理一次解决并忽略设置后的进一步咒语,因此这个操作是有效的,无论用户使用哪一个(next 或返回一个 Promise)都可以工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接