解决对多个参数值的承诺

Resolving a promise to multiple parameter values

是否有可能以链中的下一个承诺可以是采用多个参数的执行者的方式解决承诺?

例如,假设我有一个接受三个参数的函数:

function takesThreeParameters (a, b, c) {
    console.log(`${a} ${b} ${c}`);
    return 'something';
}

如果我将它包含在链中,例如其中之一:

// case 1: in a new Promise
new Promise((resolve, reject) => resolve( /* ??? */ ))
    .then(takesThreeParameters)
    .then(console.log);

// case 2: in the middle of a chain somewhere
Promise.resolve()
    .then(() => /* ??? */)
    .then(takesThreeParameters)
    .then(console.log);

// case 3: in the middle of a chain, but not as a function expression
function providesThreeValues () {
    return /* ??? */;
}
Promise.resolve()
    .then(providesThreeValues)
    .then(takesThreeParameters)
    .then(console.log);

在那些情况下(或至少在其中一种情况下)我可以 return(代替 /* ??? */)将传递 .then(takesThreeParameters) 中的所有三个参数吗?

这个问题的重要部分是我是否可以将多个参数直接传递给链中的执行程序。所以,像这样的策略可以绕过这个问题:

即我正在寻找一种方法来使 .then((a, b, c) => /* code */) 之类的东西在链中工作。

我尝试了一些手摇的东西,不出所料,它们没有用,例如对于案例 1:

我只是使用标准的 promises,无论 Node.js v16.13.1(我认为是 ES6?)。

Promiseresolve 回调只接受第一个参数,所以如果你想传递多个值,你需要传递一个数组,然后你可以将这些值作为单独的参数读取解构:

const takesThreeParameters = ([a, b, c]) => console.log(`a:${a} b:${b} c:${c}`)

const p = new Promise(res => setTimeout(res([1, 2, 3]), 2000))
p.then(takesThreeParameters)

编辑:根据@Naor Tedgi 的回答,如果您想避免修改现有函数,可以将它们包装到一个 HOF 中:

const wrap = (cb) => (args) => cb(...args)
const takesThreeParameters = (a, b, c) => console.log(`a:${a} b:${b} c:${c}`)
const wrappedFn = wrap(takesThreeParameters)

const p = new Promise(res => setTimeout(res([1, 2, 3]), 2000))
p.then(wrappedFn)

不,Promises 规范只定义了 first 参数。不能传入其他的,只能用解构或者展开来模拟。

来自 Promises/A+ spec, 2.2.2.1,强调我的:

If onFulfilled is a function:

  • it must be called after promise is fulfilled, with promise’s value as its first argument.

ES6 规范在 NewPromiseReactionJob (27.2.2.1) step 1.e 中对此进行了描述:

e. Else, let handlerResult be Completion(HostCallJobCallback(handler, undefined, « argument »)).

在这两种情况下,规范都允许单个 Promise 处理程序值。与 setTimeoutadditional arguments can be passed to the handler 等功能不同,Promises 没有这样的选项。

您至少可以避免使用 spread syntax:

重复参数列表
Promise.resolve()
    .then(providesThreeValues)
    .then(threeValues => takesThreeParameters(...threeValues))
    .then(console.log);

同样,如果您愿意编辑函数,对 takesThreeParameters 的编辑可以用 array destructuring:

进行最小化
function takesThreeParameters ([a, b, c]) {  // new brackets
    console.log(`${a} ${b} ${c}`);
    return 'something';
}

这个 hack 应该解决所有用例使用 spreadParams 函数和解析数组

function spreadParams(cb) {
    return function (args) {
       return cb(...args)
    }
}

const takesThreeParameters = spreadParams((a, b, c) => {
    console.log(`${a} ${b} ${c}`);
    return 'something';
})

new Promise((resolve, reject) => resolve([1, 2, 3]))
    .then(spreadParams(takesThreeParameters))
    .then(console.log);