简体   繁体   English

如何使用Promise.all()推迟返回函数内部正在构建的数组?

[英]How do I use Promise.all() to defer returning an array that's being built inside the function?

Below I'm attempting to assign a value, an array, to a local variable. 下面,我尝试将一个值(数组)分配给局部变量。 I'm calling a function that returns an array to get that value. 我正在调用一个返回数组以获取该值的函数。 The problem is that the Promises in the 2nd function aren't resolved until after the array has been returned to the caller. 问题在于,直到将数组返回给调用方之后,第二个函数中的Promises才被解析。 I've tried using Promise.all() on retArray but it never works for me. 我已经尝试过在retArray上使用Promise.all() ,但它对我永远都retArray When I console.log() out my someobject object the arrOfTitles field never prints out because the call to SkywalkerTitles() returns an empty array . 当我console.log()退出我的someobject对象时, arrOfTitles字段永远不会打印出来,因为对SkywalkerTitles()的调用返回了一个空数组

You can run the code here . 您可以在此处运行代码。

So how do I get someObject.arrOfTitles to get the array of titles from SkywalkerTitles() ? 那么,如何获取someObject.arrOfTitles以从SkywalkerTitles()获取标题数组?

function SkywalkerTitles(){
  let retArray = [];

  fetch('https://swapi.co/api/people/')
  .then(function(response){
    response.json()
    .then(function(result){
      return result.results[0];
    })
    .then(function(result){
       result.films.forEach(function(film){
        fetch(film)
        .then(function(response){
          response.json().then(function(result){
            console.log(result.title);
            retArray.push(result.title);
          });
        });
      })
      .catch(function(error){
        console.log(error)
      });
    });
  })
  .catch(function(error){
    console.log(error)
  });

}

function UseReturnedArray() {
  let someObject = { aThing: '', anotherThing: '', arrOfTitles: null };

  someObject.aThing = 'Thing One';
  someObject.anotherThing = 'Thing Two';
  someObject.arrOfTitles = SkywalkerTitles();

  console.log('Object With Returned Array:\n\n', JSON.stringify(someObject, null, 2));
}

UseReturnedArray();

You should take advantage of async/await, which could really clean up your code quite a bit and make it more understandable: 您应该利用async / await的优势,这实际上可以清理代码并使其更易于理解:

async function SkywalkerTitles () {
  let character = await fetch('https://swapi.co/api/people/').then(res => res.json()).then(res => res.results[0])
  return await Promise.all(character.films.map(async (film) => {
    return await fetch(film).then(res => res.json()).then(res => res.title)
  }))
}

async function UseRetrunedArray () {
  try {
    let someObject = {
      aThing: '',
      anotherThing: '',
      arrOfTitles: await SkywalkerTitles()
    }

    console.log(someObject)
  } catch (e) {
    console.error(e)
  }
}

UseRetrunedArray()

See https://repl.it/Lc2f/2 参见https://repl.it/Lc2f/2

If this looks alien to you, I suggest you read a bit into how async / await and Promise work together. 如果您觉得这有些陌生,建议您阅读一下async / awaitPromise如何一起工作。

As much as @Svenskunganka answer is complete and worthy, alternative if your environment doesn't yet support async/await AND you don't want to use a transpiler - seeing as you're already partially familiar with Promises, this code shouldn't look as foreign :p @Svenskunganka的回答是完整和有价值的,如果您的环境尚不支持异步/等待并且您不想使用转译器,则可以选择-看到您已经对Promises有所了解,则此代码不应看起来像外国:p

Your main problem is that SkywalkerTitles doesn't actually return anything (you claim it returns an empty array, it actually has no return statement, therefore the returned value is undefined 您的主要问题是SkywalkerTitles实际上没有返回任何内容(您声称它返回了一个空数组,它实际上没有return语句,因此返回的值是undefined

I've also removed the .catch code, because where you had it would actually cause issues, in that your code handles rejections, yet further down the chain the code would expect that the data was actually valid! 我还删除了.catch代码,因为在该代码中,它实际上会引起问题,因为您的代码可以处理拒绝,但在链的更下游,代码将期望数据实际上是有效的! Only a single catch almost always ever needed 几乎只需要一次捕获

function SkywalkerTitles() {
    return fetch('https://swapi.co/api/people/').then(function (response) {
        return response.json();
    }).then(function (result) {
        return result.results[0];
    }).then(function (result) {
        return Promise.all(result.films.map(function (film) {
            return fetch(film).then(function (response) {
                return response.json();
            }).then(function (result) {
                return result.title;
            });
        }));
    });
}

function UseReturnedArray() {
    SkywalkerTitles().then(function (arrOfTitles) {
        var someObject = {
            aThing: '',
            anotherThing: '',
            arrOfTitles: arrOfTitles
        };
        console.log('Object With Returned Array:\n\n', JSON.stringify(someObject, null, 2));
    }).catch(function(reason) {
        console.log(reason);
    });
}
UseReturnedArray();

Note how the promise chain is flattened compared to yours, and use of Array#map instead of Array#forEach + Array#push 请注意,与您的相比,promise链如何展平,并使用Array#map代替Array#forEach + Array#push

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

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