无极中间件

Kas*_*tin 0 javascript node.js promise

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

有没有简单的方法可以将中间件放入Promise链中?

例如,假设我们有一些可能axios.get('/users')。我们想对结果做点什么,然后再做点其他事情。假设这些动作位于应用程序的不同部分,并且我们不能将它们组合为一个功能。甚至更多,其中一些只是同步存储更新(并且不返回任何内容),而其他可能返回promise。

一个人可以写

axios
  .get('/users')
  .then((result) => {
    doSomething(result)
  })
  .then((result) => {
    doSomethingElse(result)
  })
Run Code Online (Sandbox Code Playgroud)

这将不起作用,因为第一个then不会返回承诺,因此第二个then不会收到结果。正确的代码(用于没有承诺的同步操作)是:

axios
  .get('/users')
  .then((result) => new Promise((resolve, reject) => {
    doSomething(result)
    resolve(result)
  }))
  .then(result) => new Promise((resolve, reject) => {
    doSomethingElse(result)
    resolve(result)
  })
  ...etc...
Run Code Online (Sandbox Code Playgroud)

但是我不喜欢这样。我一个人吗?我想要类似的东西:

axios
  .get('/users')
  .thenMiddleware(doSomething)
  .then((result) => {
    doSomethingElse()
  })
Run Code Online (Sandbox Code Playgroud)

这意味着我们要doSomething使用的结果运行,get('/users')然后,如果没有错误,我们要再次使用下一个结果调用下一个链函数get('/users')

关于错误:只有在操作返回一个承诺并且该承诺被拒绝的情况下,我才会考虑错误。

有道理吗?

那就是我写的函数:

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)
    }
  })
}
Run Code Online (Sandbox Code Playgroud)

我们可以使用它像这样。那是正确的方法还是我遗漏了一些对我而言有用的承诺?

T.J*_*der 5

您正在寻找的中间件概念是then(或catch)回调本身。then(和catch)返回一个新的 Promise(我们称之为newP)。如果您提供给then/ 的回调函数catch返回了一个thenPPromise,则该回调函数将作为该回调函数返回的Promise的奴隶。如果回调返回不可设置的值(例如,不是承诺),thenP则使用该值进行解析。如果回调引发异常,thenP则该异常将被拒绝。

正确的代码(用于没有承诺的同步动作)是

不,正确的代码是从中返回then

axios
  .get('/users')
  .then(result => {
    return doSomething(result);
  })
  .then(result => {
    return doSomethingElse(result);
  });
Run Code Online (Sandbox Code Playgroud)

如果只是函数调用,您也可以将其编写为:

axios
  .get('/users')
  .then(doSomething)
  .then(doSomethingElse);
Run Code Online (Sandbox Code Playgroud)

如果doSomethingdoSomethingElse也是异步的,请确保它们返回诺言。如果不是,则上述方法有效,或者您可以将其组合:

// Assumes `doSomething` is not asynchronous
axios
  .get('/users')
  .then(result => doSomethingElse(doSomething(result)));
Run Code Online (Sandbox Code Playgroud)

在评论中,您询问:

如果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);
  });
Run Code Online (Sandbox Code Playgroud)

要么

// (2.1) If `doSomething` IS asynchronous and you want to wait for it but you
// don't want its result
axios
  .get('/users')
  .then(result => {
    return doSomething(result).then(result);
  })
  .then(result =>
    return doSomethingElse(result);
  });
Run Code Online (Sandbox Code Playgroud)

后者也可以写成:

// (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);
Run Code Online (Sandbox Code Playgroud)

请注意,(2.1)和(2.2)仍将拒绝doSomething。如果要完全忽略其中发生的情况,则:

// (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);
Run Code Online (Sandbox Code Playgroud)

会将拒绝转换为的分辨率result


旁注:请记住,承诺的规则之一是您将承诺退还给呼叫者,或者您自己处理拒绝。上面没有拒绝处理程序,但是您需要在生产代码中使用它们(或者您需要将链的结果返回给具有拒绝处理程序的对象)。