Javascript 承诺中间件

Javascript 承诺中间件,javascript,node.js,promise,Javascript,Node.js,Promise,最近我不得不写一些奇怪的代码。我不确定,也许我在重新发明轮子 有没有简单的方法将中间件放入承诺链 假设我们有一些承诺,例如,可能是axios.get'/users'。 我们想对结果做点什么,然后再做点别的。 假设这些操作位于应用程序的不同部分,并且我们不能将它们组合成一个函数。 更重要的是,其中一些只是同步的商店更新,不返回任何内容,另一个可能返回承诺 可以写 axios .get('/users') .then((result) => { doSomething(resu

最近我不得不写一些奇怪的代码。我不确定,也许我在重新发明轮子

有没有简单的方法将中间件放入承诺链

假设我们有一些承诺,例如,可能是axios.get'/users'。 我们想对结果做点什么,然后再做点别的。 假设这些操作位于应用程序的不同部分,并且我们不能将它们组合成一个函数。 更重要的是,其中一些只是同步的商店更新,不返回任何内容,另一个可能返回承诺

可以写

axios
  .get('/users')
  .then((result) => {
    doSomething(result)
  })
  .then((result) => {
    doSomethingElse(result)
  })
这不起作用,因为第一个然后不返回承诺,所以第二个然后将不会收到结果。 无承诺同步操作的正确代码为:

axios
  .get('/users')
  .then((result) => new Promise((resolve, reject) => {
    doSomething(result)
    resolve(result)
  }))
  .then(result) => new Promise((resolve, reject) => {
    doSomethingElse(result)
    resolve(result)
  })
  ...etc...
但我不喜欢这样。我一个人吗?我想要一些类似于:

axios
  .get('/users')
  .thenMiddleware(doSomething)
  .then((result) => {
    doSomethingElse()
  })
这意味着我们要用get'/users'的结果运行doSomething,如果没有错误,我们要用get'/users'的结果再次调用下一个chain函数

关于错误:我只会考虑错误,如果一个行动返回一个承诺,这个承诺拒绝。 这有意义吗

这就是我写的函数:

const promiseMiddleware = (target) => function(...args) {
  return new Promise((resolve, reject) => {
    if (typeof target === 'function') {
      target = target.apply(this, args)
    }
    if (typeof target === 'object' && typeof target.then === 'function') {
      // Middleware does not count the result of inner promise, it triggers the promise chain to continue with the incomming data instead.
      // But if the inner promise rejects, middleware returns an inner error.
      target.then((targetResult) => {
        // So we don't use targetResult here, we just resolve with the incomming args.
        resolve.apply(this, args)
      }).catch(reject)
    } else {
      resolve.apply(this, args)
    }
  })
}

我们可以像这样使用它。这是正确的方法吗?还是我忽略了在我的例子中可以使用的一些明显的承诺?

您正在寻找的中间件概念是then或catch回调本身。然后,抓住一个新的承诺,让我们称之为新的。如果您提供给then/catch的回调返回承诺或更一般的thenable,则thenP将解析为回调返回的一个,这意味着它将根据该承诺/thenable的功能得到满足或拒绝。如果回调返回一个非thenable的值,例如,不是承诺,则使用该值来实现p。如果回调引发异常,则会将p与该异常一起拒绝

如果术语thenable不太熟悉,或者您不清楚fulfill和resolve之间的区别,我会在我的博客中使用promise术语

没有承诺的同步操作的正确代码是

否,正确的代码是从中返回:

如果只是函数调用,也可以简单地编写:

axios
    .get('/users')
    .then(doSomething)
    .then(doSomethingElse);
如果doSomething和doSomethingElse也是异步的,请确保它们返回承诺。如果没有,则上述方法有效,或者您可以将其结合使用:

// Assumes `doSomething` is not asynchronous
axios
    .get('/users')
    .then(result => doSomethingElse(doSomething(result)));
在您询问的评论中:

如果doSomething不返回任何值怎么办?那么doSomethingElse将不会收到get

承诺的主要概念之一是,它们是一条管道,管道中的每一步都可能改变通过它的内容。如果管道中需要一个不转换分辨率值的段,则可以将其与下一个段(如果不是异步的)组合,或者让该段返回它接收到的内容(如果是):

// (1) If `doSomething` ISN'T asynchronous or it is but you don't care
// that `doSomething` and `doSomethingElse` run in parallel if it is
axios
    .get('/users')
    .then(result => {
        doSomething(result);
        return doSomethingElse(result);
    });

后者也可以写成:

// (2.2) Also if `doSomething` IS asynchronous and you want to wait for it but
// you don't want its result
axios
    .get('/users')
    .then(result => doSomething(result).then(result))
    .then(doSomethingElse);
请注意,2.1和2.2仍将考虑剂量测定的拒绝。如果你想完全忽略其中发生的事情,那么:

// (3) If `doSomething` IS asynchronous and you want to wait for it but
// you don't want its result AND you want to ignore rejections
axios
    .get('/users')
    .then(result => doSomething(result).then(result, result))
    // Change is here -----------------------------^^^^^^^^
    .then(doSomethingElse);
将拒绝转换为具有结果的解决方案


旁注:记住承诺的规则之一是,你要么将承诺退还给你的来电者,要么自己处理拒绝。上面没有拒绝处理程序,但是您需要在生产代码中使用它们,或者您需要将链的结果返回到具有拒绝处理程序的内容。

当您处于承诺链中时,您不必返回承诺。如果在链内执行异步调用,则只需返回承诺

你可以这么做

axios
  .get('/users')
  .then((result) => {
    return doSomething(result);
  })
  .then((result) => {
    return doSomethingElse(result);
  })
假设您有一个异步回调风格的调用,那么您应该执行该调用

axios
  .get('/users')
  .then((result) => {
    return new Promise((resolve, reject) => {
      doSomething(result, (err, result) => {
         return err ? reject(err) : resolve(result);
      });
    });
  })
  .then((result) => {
    return doSomethingElse(result);
  })
这很简单

如果您编写了中间件doSomething函数,那么只需让它返回结果而不改变它。例如,

function doSomething(result){
  // here i do tons of things with the result but i don't mutate it
  return result;
}
那么您的代码可能看起来像

axios
  .get('/users')
  .then(doSomething)     // this will pass result to the next then
  .then(doSomethingElse) // stage automatically wrapped in a promise
顺便说一句,你不需要做like.thenres=>{doStgres}只要做like.thendoStg就行了

然而,如果你对中间件的doSomething功能没有任何控制权,那么你所要做的就是

axios
  .get('/users')
  .then(res => (doSomething(res), res)) // this will pass result to the next then
  .then(doSomethingElse)                // stage automatically wrapped in a promise
注意:当您只有少量说明时,请使用箭头功能。我不喜欢带箭头的大括号,而是更喜欢逗号运算符。所以,

res => (doSomething(res), res)
本质上与,

res => {doSomething(res);
        return res;}

抱歉,这里有几个输入错误,您可能必须点击刷新。好的,但是如果doSomething没有返回任何值呢?那么doSomethingElse无论如何都不会收到get的结果。@Kasheftin您只需要让它返回值,比如说,包装它:value=>{doSomething;return value;}@Kasheftin:AKX基本上是正确的,这取决于doSomething是否是异步的,以及是否要等待它的结果。为了更全面地回答这个问题,我增加了答案。
res => (doSomething(res), res)
res => {doSomething(res);
        return res;}