你如何正确地从承诺中返回多个值?

Der*_*ler 70 javascript promise q

我最近遇到过几次某种情况,我不知道如何正确解决.假设以下代码:

somethingAsync()
  .then( afterSomething )
  .then( afterSomethingElse )

function afterSomething( amazingData ) {
  return processAsync( amazingData );
}
function afterSomethingElse( processedData ) {
}
Run Code Online (Sandbox Code Playgroud)

现在可能会出现我想要访问的amazingData情况afterSomethingElse.

一个明显的解决方案是返回一个数组或一个哈希afterSomething,因为,你只能从一个函数返回一个值.但我想知道是否有办法afterSomethingElse接受2个参数并同样调用它,因为这似乎更容易记录和理解.

我只是想知道这种可能性,因为它有Q.spread类似于我想要的东西.

Ben*_*aum 73

您无法解决具有多个属性的承诺,就像您无法从函数返回多个值一样.承诺在概念上代表一段时间内的值,因此当您可以表示复合值时,您不能在承诺中放置多个值.

一个承诺固有地解决了单个值 - 这是Q如何工作,Promises/A +规范如何工作以及抽象如何工作的一部分.

你可以得到的最接近的是使用Q.spread和返回数组或使用ES6解构(如果它是支持的,或者你愿意使用像BabelJS这样的转换工具).

至于在承诺链中传递上下文,请参阅Bergi的优秀规范.

  • 使用具有多个属性的对象解析有什么问题?似乎是一种从解决方案中获取多个值的简单方法. (11认同)
  • @AustinHemmelgarn 那是错误的, `Promise.all` 满足[用数组](https://www.ecma-international.org/ecma-262/10.0/index.html#sec-performpromiseall)。在 `Promise.all([a,b]).then((a, b) =>` 中 `b` 是 `undefined`。这就是为什么你需要做 `.then(([a, b]) => ` 这是一个解构赋值 (6认同)
  • 这样做完全没问题 (4认同)

Ale*_*lva 25

你只能传递一个值,但它可以是一个具有多个值的数组,例如:

function step1(){
  let server = "myserver.com";
  let data = "so much data, very impresive";
  return Promise.resolve([server, data]);
}
Run Code Online (Sandbox Code Playgroud)

另一方面,您可以使用ES2015 的解构表达式来获取各个值.

function step2([server, data]){
  console.log(server); // print "myserver.com"
  console.log(data);   // print "so much data, very impresive"
  return Promise.resolve("done");
}
Run Code Online (Sandbox Code Playgroud)

称这两个承诺,链接他们:

step1()
.then(step2)
.then((msg)=>{
  console.log(msg); // print "done"
})
Run Code Online (Sandbox Code Playgroud)

  • 它称为* destructuring *,而不是“ deconstructor”,它不是运算符:-/ (4认同)
  • 顺便说一句,你可以在参数中使用解构权:`function step2([server,data]){...` - 这样你也可以避免分配给隐式全局变量.你真的应该在你的例子中使用`return`或`Promise.resolve`,而不是`new Promise`构造函数. (2认同)

Kev*_*eid 18

您可以返回包含两个值的对象 - 这没有任何问题.

另一个策略是通过闭包来保持价值,而不是通过它:

somethingAsync().then(afterSomething);

function afterSomething(amazingData) {
  return processAsync(amazingData).then(function (processedData) {
    // both amazingData and processedData are in scope here
  });
}
Run Code Online (Sandbox Code Playgroud)

完全而不是部分内联形式(等效,可以说更一致):

somethingAsync().then(function (amazingData) {
  return processAsync(amazingData).then(function (processedData) {
    // both amazingData and processedData are in scope here
  });
}
Run Code Online (Sandbox Code Playgroud)

  • 可以在另一个`then`中返回一个'then'吗?不是_anti-pattern_吗? (2认同)

Red*_*edu 7

无论您从 Promise 返回什么,都将被包装到 Promise 中,并在下一.then()阶段解开。

当您需要返回一个或多个承诺以及一个或多个同步值时,例如:

Promise.resolve([Promise.resolve(1), Promise.resolve(2), 3, 4])
       .then(([p1,p2,n1,n2]) => /* p1 and p2 are still promises */);
Run Code Online (Sandbox Code Playgroud)

在这些情况下,必须使用Promise.all()getp1p2Promise 在下一.then()阶段解开包装,例如

Promise.resolve(Promise.all([Promise.resolve(1), Promise.resolve(2), 3, 4]))
       .then(([p1,p2,n1,n2]) => /* p1 is 1, p2 is 2, n1 is 3 and n2 is 4 */);
Run Code Online (Sandbox Code Playgroud)


jem*_*oii 5

你可以做两件事,返回一个对象

somethingAsync()
    .then( afterSomething )
    .then( afterSomethingElse );

function processAsync (amazingData) {
     //processSomething
     return {
         amazingData: amazingData, 
         processedData: processedData
     };
}

function afterSomething( amazingData ) {
    return processAsync( amazingData );
}

function afterSomethingElse( dataObj ) {
    let amazingData = dataObj.amazingData,
        processedData = dataObj.proccessedData;
}
Run Code Online (Sandbox Code Playgroud)

使用范围!

var amazingData;
somethingAsync()
  .then( afterSomething )
  .then( afterSomethingElse )

function afterSomething( returnedAmazingData ) {
  amazingData = returnedAmazingData;
  return processAsync( amazingData );
}
function afterSomethingElse( processedData ) {
  //use amazingData here
}
Run Code Online (Sandbox Code Playgroud)


小智 5

只需创建一个对象并从该对象中提取参数即可。

let checkIfNumbersAddToTen = function (a, b) {
return new Promise(function (resolve, reject) {
 let c = parseInt(a)+parseInt(b);
 let promiseResolution = {
     c:c,
     d : c+c,
     x : 'RandomString'
 };
 if(c===10){
     resolve(promiseResolution);
 }else {
     reject('Not 10');
 }
});
};
Run Code Online (Sandbox Code Playgroud)

从 promiseResolution 中提取参数。

checkIfNumbersAddToTen(5,5).then(function (arguments) {
console.log('c:'+arguments.c);
console.log('d:'+arguments.d);
console.log('x:'+arguments.x);
},function (failure) {
console.log(failure);
});
Run Code Online (Sandbox Code Playgroud)