简体   繁体   English

装饰Javascript Promise.then以便参数函数接收附加参数

[英]Decorate Javascript Promise.then so that the argument function receive additional parameter

I have the following code using ES6 Promise : 我使用ES6 Promise有以下代码:

const ctx = {}
Promise.resolve()
  .then(() => doSomethingWith(ctx))
  .then((retValue) => doSomethingElseWith(retValue, ctx))

I would like to be able to do something like this : 我希望能够做到这样的事情:

const ctx = {}
using(ctx)
   .then((ctx) => doSomethingWith(ctx))
   .then((retValue, ctx) => doSomethingElseWith(retValue, ctx))

For the first then , I have something like this : 对于第一个then ,我有这样的事情:

function using(ctx) {
  const p = Promise.resolve()
  p.then = (fn) => withCtx(fn, ctx)
  return p
}

function withCtx (fn, ctx) {
  const p = new Promise((resolve) => {
    resolve(fn.apply(this, [ctx]))
  })
  return p
}

But I would like it to handle the case of the second then that takes both the previous promise returned value and the context... How could I have this part : 但我希望它能够处理第二种情况然后同时接受前一个承诺返回值和上下文......我怎么能有这个部分:

fn.apply(this, [ctx]) // want previous promise returned value and ctx here !

handle the case fn already takes a parameter we want to propagate... the retValue case describe above. 处理案例fn已经采用了我们想要传播的参数...上面描述的retValue案例。

Any idea ? 任何想法 ? (the use case I want to cover after is to be able to stop the Promise chain at any time, persist values on disk and restart at any time with altered context restored from disk) (我想要覆盖的用例是能够随时停止Promise链,在磁盘上保留值并随时从磁盘恢复更改的上下文重新启动)

To be honest I think it's confusing and probably an anti pattern, but can you pass mutable state between promises simply by adding an extra then 说实话,我认为这是令人困惑的,可能是一种反模式,但你可以简单地通过添加一个额外的then在承诺之间传递可变状态

Promise.resolve({}) 
.then(ctx => doSomethingWith(ctx)
  .then(ret => ({ret, ctx})))
.then(({ret, ctx}) => doSomethingElseWith(ret, ctx))

The second then is inside the first one and therefore has a closure on the input state, which it can decorate with the transformed value, before passing the mutated context to the next phase. 第二个then在第一个内部,因此在输入状态上有一个闭包,它可以用变换后的值进行修饰,然后将变异的上下文传递给下一个阶段。 This achieved without leaking any references to the global context. 这不会泄露任何对全球背景的引用。

To show what it looks like if you extend the pattern... 展示如果扩展模式的样子......

function trans (that, y) {
  console.dir(y);
  return new Promise(res =>
    setTimeout(res.bind(null, that.op(y)), 1000)
  )
}

Promise.resolve({ret: 0, ctx: {op: _ => _ + 2}})
  .then(({ret, ctx}) => trans(ctx, ret)
    .then(ret =>({ ret, ctx}))
  )
  .then(({ret, ctx}) => trans(ctx, ret)
    .then(ret =>({ ret, ctx}))
  )
  .then(({ret, ctx}) => trans(ctx, ret)
    .then(ret =>({ ret, ctx}))
  )
  .then(({ret, ctx}) => trans(ctx, ret)
    .then(ret =>({ ret, ctx}))
  )
  .then(ctx => console.dir(ctx));
  .catch(console.log.bind(console));

The following may be the pattern you are looking for: 以下可能是您正在寻找的模式:

something0()
  .then(result0 => something1(ctx, result0)
    .then(result1 => something2(ctx, result0, result1)
      .then(result2 => something3(ctx, result0, result1, result2))
    )
  )
;

Yes, it is a sort of pyramid of doom, but there's no other way to keep the previous results in scope for use later down the chain. 是的,它是一种厄运的金字塔,但没有其他方法可以将以前的结果保留在以后使用的范围内。

Worth keeping in mind that if you need to pass more than one value through a computation, then you can simply return a list (Array) of multiple values/results from your .then functions: 值得记住的是,如果您需要通过计算传递多个值,那么您只需从.then函数返回多个值/结果的列表(Array):

Promise.resolve(6)
  .then( x => [x+6, x] )
  .then( ([latestVal, oldvalue]) => /*whatever*/ );

There's nothing wrong with this approach and there are various other methods (like unapply/apply you can use to modify your handler functions in order to receive/work with Arrays as return types (which you should really think of as nested types: you're now working over a Promise[Array[...values]] which is actually pretty common pattern. 这种方法没有任何问题,还有其他各种方法(比如unapply/apply你可以用来修改你的处理函数,以便接收/使用Arrays作为返回类型(你应该把它当作嵌套类型:你是现在正在研究Promise [Array [... values]],这实际上是非常常见的模式。

Note that this works even if some of the values are themselves derived from async operations: just pass them into Promise.all and it will turn an Array of values/Promises into a Promise of an Array, and you can then just destructure the Array to get at your various results. 请注意,即使某些值本身是从异步操作派生的,这也可以工作:只需将它们传递给Promise.all,它就会将一个值/ Promise数组转换为一个Array的Promise,然后你可以将Array解构为得到你的各种结果。

Promise.resolve(6)
  .then( x => Promise.all([additionApi(x), x]) )
  .then( ([latestVal, ...rest]) => Promise.all( additionApi(x).concat(latest, rest) ) )
  .then( ([latestVal, ...rest]) => Promise.all( additionApi(x).concat(latest, rest) ) );
  //...etc.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM