Объединить массивы в функции карты

У меня есть проблема, или, по крайней мере, у меня нет решения.

Я получаю некоторые вызовы API через карту, и я могу console.log все результаты, и это здорово, но проблема в том, что я хочу объединить все результаты в один массив.

var alpha = ['a', 'b', 'c', 'd', 'e'];

alpha.map(alpha => {
 fetch(`https://myurl.com/api/members/page?prefix=${alpha}`)
 .then(res => res.json())
 .then(data => matches.push)
 .then(() => console.log(matches))
})

Я думаю, мне нужно сделать какое-то ожидание или что-то в этом роде?

Мой ответ от API выглядит так:

{"list_complete":true,"keys":
    [
        {
            "username": "name.com",
            "uuid": "-47c9-88b6-2474090c7927",
            "user_type": 1,
            "subscribed": "false",
            "lastLogin": 1611066809086,
            "profile": {
                "name": "Name Lastname",
                "email": "name.com",
                "uuid": "3e92f458-6331-2-88b6-2474090c7927",
                "address": "",
                "history": [
                    {
                        "titleId": "5fac58f764e6710017411e79",
                        "posterUrl": "url.jpg",
                        "displayName": "Guns N ´ Roses - Appetite for Democracy",
                        "t": 0,
                        "d": 8492.2
                    },
                    {
                        "titleId": "5f7eadb3963c170017a919f3",
                        "posterUrl": "url.jpg",
                        "displayName": "Frank Zappa - Apostrophe Overnite Sensation (Classic Albums)",
                        "t": 7.728575,
                        "d": 2974.9
                    },
                    {
                        "titleId": "5e4463a395c832405e7effc0",
                        "posterUrl": "url.jpg",
                        "displayName": "Bob Marley - Uprising Live!",
                        "t": 3285.406821,
                        "d": 6807.7
                    },
                    {
                        "titleId": "5f80c6d0045fdf0017735019",
                        "posterUrl": "url.jpg",
                        "displayName": "Van Morrison - In Concert",
                        "t": 3610.529879,
                        "d": 4558.29
                    },
                    {
                        "titleId": "5fa85aba9c4a1900177e5cf9",
                        "posterUrl": "url.jpg",
                        "displayName": "Iron Maiden - En Vivo!",
                        "t": 2522.988949,
                        "d": 3380.5
                    },
                    {
                        "titleId": "5f719cb75d994e0017b429c5",
                        "posterUrl": "url.jpg",
                        "displayName": "Placebo - Placebo Live At The O2 Brixton Academy",
                        "t": 1426.589863,
                        "d": 5061.89
                    },
                    {
                        "titleId": "5fb3fd1731be640017c2f878",
                        "posterUrl": "https://slam-assets.s3.eu-north-1.amazonaws.com/staging/5fb3fd1731be640017c2f878/cover/1606214166013_nirvanastaende.jpg",
                        "displayName": "Nirvana - Nevermind (Classic Albums)",
                        "t": 0,
                        "d": 2948.69
                    }
                ],
                "favourites": [
                    "5f9039ed1279d600170378c2",
                    "5facf94364e6710017411e7d",
                    "5e4463a395c832405e7effc0"
                ]
            },
            "subscription": null
        }
    ]
}

И данные, которые я хочу собрать, находятся в массиве под названием история для каждого пользователя.


person Mikael Blytung    schedule 08.03.2021    source источник
comment
Изучите Promise.all и связанные методы. . Как именно вы планируете использовать полученные значения?   -  person Sebastian Simon    schedule 09.03.2021
comment
Прохладно. благодарю вас. Посмотрю. Когда я соберу все данные, я объединим всю историю пользователей в одну.   -  person Mikael Blytung    schedule 09.03.2021
comment
Если matches — это массив, matches.push мало что даст. Вам понадобится .then(matches.push), если вы хотите поместить data в matches (или then(data => { matches.push(data); }), чтобы не получить ответ новой длины matches (вывод push).   -  person Heretic Monkey    schedule 09.03.2021
comment
См. здесь пример использования Promise.all(): flaviocopes.com/how-to- ожидание-несколько-обещаний-javascript   -  person Carsten Massmann    schedule 09.03.2021
comment
@HereticMonkey Я знаю, вы больше не можете редактировать комментарий, но для записи .then(matches.push) не будет работать из-за контекста метода быть потерянным; это должно быть .then(matches.push.bind(matches)).   -  person Sebastian Simon    schedule 09.03.2021


Ответы (3)


Насколько я понимаю, вы получаете data в результате выборки, и вы получите столько же возвратов data для элементов массива alpha. Вы хотели бы объединить результаты вашего объекта history из данных в один одномерный массив. Это означает, что ваш целевой массив выглядит так:

histories = [{},{},{} ... ]

Где каждый объект {} является элементом истории.

Чтобы выполнить требуемую операцию, нам нужно сначала получить доступ к элементам keys и выполнить итерацию по всем из них, извлекая содержимое history из каждого из них. Однако вы упомянули, что history может существовать или не существовать для пользователя, поэтому нам нужно проверить его существование.

Итак, резюмируя:

  • Нам нужно перебрать все элементы keys

  • Нам нужно проверить, существует ли в вышеупомянутых элементах history, прежде чем пытаться что-то с ним сделать.

Мы можем выполнить первое действие, используя метод forEach() для data.keys, а простой if (element.profile.history) для проверки наличия history:

var alpha = ['a', 'b', 'c', 'd', 'e'];
const histories = [];

alpha.map(alpha => {
    fetch(`https://myurl.com/api/members/page?prefix=${alpha}`)
        .then(res => res.json())
        .then(data => data.keys.forEach(function (e) { //Iterate through the keys
            if (e.profile.history) { //If history is present
                histories.push(...e.profile.history); //Pushing to array with spread sytnax
            }
        })
        )
})

Чтобы иметь один массив со всеми history элементами, мы использовали расширенный синтаксис ..., вы можете узнать больше об этом здесь

Итак, вывод:

console.log(histories)

Затем будет получено:

[
  {
    titleId: '5fac58f764e6710017411e79',
    posterUrl: 'url.jpg',
    displayName: 'Guns N ´ Roses - Appetite for Democracy',
    t: 0,
    d: 8492.2
  },
  {
    titleId: '5f7eadb3963c170017a919f3',
    posterUrl: 'url.jpg',
    displayName: 'Frank Zappa - Apostrophe Overnite Sensation (Classic Albums)',
    t: 7.728575,
    d: 2974.9
  },
  {
    titleId: '5e4463a395c832405e7effc0',
    posterUrl: 'url.jpg',
    displayName: 'Bob Marley - Uprising Live!',
    t: 3285.406821,
    d: 6807.7
  },
...
]
person BiOS    schedule 08.03.2021
comment
Такая большая помощь. Большое спасибо еще раз. Конечно, я проголосовал за него и отметил его как решенный. Я многому научился и многое испытал. Так что я благодарен. Да, об этом я тоже думал, но не могу получить к нему доступ снаружи, когда пытаюсь его зациклить. - person Mikael Blytung; 09.03.2021
comment
Никаких проблем! Большое спасибо! Что касается этой другой проблемы: histories на самом деле доступен из-за пределов функции map(), вы можете попробовать сами, выполнив что-то вроде console.log(histories[0].titleId) вне карты (), так как это напечатает titleId первой истории. Это более или менее то, что вы хотите сделать? - person BiOS; 09.03.2021

Вы пробовали вставлять их в массив?

var alpha = ['a', 'b', 'c', 'd', 'e'];
const results = [];

alpha.map(alpha => {
fetch(`https://myurl.com/api/members/page?prefix=${alpha}`)
  .then(res => res.json())
  .then(data => results.push(data))
})
person Cromix    schedule 08.03.2021
comment
Да, тогда я получаю массив, но все равно в том массиве у меня 5 разных. Хотите скомпилировать его в один массив. - person Mikael Blytung; 09.03.2021
comment
попробуйте изменить: then(data =› results.push(data)) на: .then(data =› results.push(…data)) - person Dan Levin; 09.03.2021

Там, где вы используете alpha.map, я бы предложил alpha.forEach, так как вы только зацикливаетесь, а не отображаете.

Вы можете использовать await вместо .then, но именно так вы обрабатываете Promise, возвращаемый из await.


const urls = [/* your urls here */];
const matches = [];
urls.forEach( url => {
  const res = await fetch(url);
  const json = await res.json();
  matches.push(json);
});
console.log(matches);

Используя существующий стиль, поместите data в массив matches и зарегистрируйтесь, как только закончите:

var alpha = ['a', 'b', 'c', 'd', 'e'];
var matches = [];
alpha.forEach(alpha => {
 fetch(`https://myurl.com/api/members/page?prefix=${alpha}`)
 .then(res => res.json())
 .then(data => matches.push(data))
});
console.log(matches);

Вы можете использовать Promise.all для параллельного выполнения вызовов fetch, но это уже другая история.

Я думаю, возможно, ваш JSON вернулся в виде массива, так что в итоге вы получите массив массивов? Взгляните на Array.concat, и используйте его, чтобы добавить res.json в массив matches.

person Lee Goddard    schedule 09.03.2021