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

时间:2017-09-26 04:27:35

标签: javascript arrays promise es6-promise

下面我试图将一个值,一个数组赋给一个局部变量。我正在调用一个返回数组的函数来获取该值。问题是第二个函数中的Promises直到数组返回给调用者之后才得到解析。我尝试在Promise.all()上使用retArray,但它对我来说无效。当我console.log()我的someobject对象后,arrOfTitles字段永远不会打印出来,因为对SkywalkerTitles() 的调用会返回一个空数组

您可以运行代码here

那么如何让someObject.arrOfTitlesSkywalkerTitles()获取标题数组?

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

2 个答案:

答案 0 :(得分:1)

你应该利用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()

请参阅https://repl.it/Lc2f/2

如果这对您来说很陌生,建议您仔细阅读async / awaitPromise如何协同工作。

答案 1 :(得分:1)

尽管@Svenskunganka的答案是完整且有价值的,但如果你的环境还不支持异步/等待并且你不想使用转换器,则可以选择 - 因为你已经熟悉了Promises,这段代码不应该看起来像外国人:p

你的主要问题是SkywalkerTitles实际上没有返回任何内容(你声称它返回一个空数组,它实际上没有return语句,因此返回的值是undefined

我还删除了.catch代码,因为你所拥有的代码实际上会导致问题,因为你的代码会处理拒绝,而在代码链的下游,代码会期望数据实际上是有效的!几乎总是只需要一次捕获

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

请注意,与您的相比,承诺链是如何展平的,并使用Array#map代替Array#forEach + Array#push