装饰Javascript Promise.then,使参数函数获得额外的参数

我有以下使用ES6 Promise的代码:

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

我希望能够做到这样的事情:

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

首先,我有这样的东西:

 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 } 

但我希望它能够处理第二个的情况,那么同时使用前一个promise的返回值和上下文…我怎么能有这个部分:

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

处理情况fn已经接受了我们要传播的参数… retValue情况如上所述。

任何想法 ? (我想要覆盖的用例是能够随时停止Promise链,在磁盘上保留值并在任何时候重新启动,并从磁盘恢复已更改的上下文)

说实话,我认为这是混乱,可能是反模式,但你可以通过承诺之间的可变状态,只需增加一个额外的

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

第二个是在第一个内部,因此在input状态上有一个闭包,在将变化的上下文传递到下一个阶段之前,它可以用变换后的值进行修饰。 这在不泄露对全球背景的任何提及的情况下实现。

为了显示延长模式的样子

 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)); 

以下可能是您正在寻找的模式:

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

是的,这是一种厄运的金字塔,但是没有其他办法可以保留以前的结果在后面的使用范围之内。

值得注意的是,如果您需要通过计算传递多个值,那么您可以简单地从.then函数返回多个值/结果的列表(数组):

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

这种方法没有什么问题,还有其他各种方法(比如像unapply/apply你可以用来修改你的处理函数来接受/使用数组作为返回types(你应该真的把它看作嵌套types):现在在一个Promise [Array [… values]]上工作,这实际上是很常见的模式。

请注意,即使某些值本身是从asynchronous操作派生出来的,也可以工作:只需将它们传递给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.