Обработка обещаний во вложенных циклах - PullRequest
0 голосов
/ 20 сентября 2018

Я новичок в Promise.У меня есть сценарий, где список объектов внутри другого списка объектов должен быть обновлен на основе ответа от внешнего API.

Я попытался смоделировать пример сценария, как показано ниже.В приведенном ниже коде у меня есть список полетов, где массив destlist внутри массива «Полеты» должен быть обновлен путем добавления новых полей, которые будут взяты из массива пользователей на основе userId.Ниже приведен кодовый адрес URL.

const flights = [
  {
    data: {
      legid: 1,
      name: "A380",
      destlist: [
        {
          city: "city1",
          userId: 1
        },
        {
          city: "city2",
          userId: 2
        }
      ]
    }
  },
  {
    data: {
      legid: 2,
      name: "A380",
      destlist: [
        {
          city: "city1",
          userId: 2
        }
      ]
    }
  }
];

const users = [
  {
    id: 1,
    name: "Andrew",
    schoolId: 101
  },
  {
    id: 2,
    name: "Jessica",
    schoolId: 999
  }
];

const getUser = id => {
  return new Promise((resolve, reject) => {
    const user = users.find(user => user.id === id);
    if (user) {
      setTimeout(() => resolve(user), 1000);
    } else {
      setTimeout(() => reject(`Unable to find user with id of ${id}.`), 1000);
    }
  });
};

prettyJSON(
  Promise.all(
    flights.map(function(flt) {
      return Promise.all(
        flt.data.destlist.map(function(item) {
          getUser(item.userId)
            .then(us => (item.name = us.name))
            .catch(err => console.log(err));
          return flt;
        })
      );
    })
  ).then(function(data) {
    prettyJSON(data);
  })
);

function prettyJSON(obj) {
  console.log(JSON.stringify(obj, null, 2));
}

https://codepen.io/prabuj201987/pen/mGvRjL?editors=1012

Токовый выход

    [
      [
        {
          'data': {
            'legid': 1,
            'name': 'A380',
            'destlist': [
              {
                'city': 'city1',
                'userId': 1
              },
              {
                'city': 'city2',
                'userId': 2
              }
            ]
          }
        },
        {
          'data': {
            'legid': 1,
            'name': 'A380',
            'destlist': [
              {
                'city': 'city1',
                'userId': 1
              },
              {
                'city': 'city2',
                'userId': 2
              }
            ]
          }
        }
      ],
      [
        {
          'data': {
            'legid': 2,
            'name': 'A380',
            'destlist': [
              {
                'city': 'city1',
                'userId': 2
              }
            ]
          }
        }
      ]
    ]

Ожидаемый выход

  [
  [
    {
      "data": {
        "legid": 1,
        "name": "A380",
        "destlist": [
          {
            "city": "city1",
            "userId": 1,
            "name": "Andrew"
          },
          {
            "city": "city2",
            "userId": 2,
            "name": "Jessica"
          }
        ]
      }
    },
    {
      "data": {
        "legid": 1,
        "name": "A380",
        "destlist": [
          {
            "city": "city1",
            "userId": 1,
            "name": "Andrew"
          },
          {
            "city": "city2",
            "userId": 2,
            "name": "Jessica"
          }
        ]
      }
    }
  ],
  [
    {
      "data": {
        "legid": 2,
        "name": "A380",
        "destlist": [
          {
            "city": "city1",
            "userId": 2,
            "name": "Jessica"
          }
        ]
      }
    }
  ]
]

Нужен совет, как это сделать.

Ответы [ 3 ]

0 голосов
/ 20 сентября 2018

Если бы вы могли использовать async / await, было бы проще представить и реализовать более читаемое решение, подобное этому

Promise.all(flights.map(async flight => {
  const destlist = flight.data.destlist

  const updatedDestList = await Promise.all(destlist.map(async dest => {
    const user = await getUser(dest.userId)

    dest.name = user.name

    return dest
  }))

  flight.destlist = updatedDestList

  return flight
}))

Полный рабочий пример

const flights = [
  {
    data: {
      legid: 1,
      name: "A380",
      destlist: [
        {
          city: "city1",
          userId: 1
        },
        {
          city: "city2",
          userId: 2
        }
      ]
    }
  },
  {
    data: {
      legid: 2,
      name: "A380",
      destlist: [
        {
          city: "city1",
          userId: 2
        }
      ]
    }
  }
];

const users = [
  {
    id: 1,
    name: "Andrew",
    schoolId: 101
  },
  {
    id: 2,
    name: "Jessica",
    schoolId: 999
  }
];

const getUser = id => {
  return new Promise((resolve, reject) => {
    const user = users.find(user => user.id === id);
    if (user) {
      setTimeout(() => resolve(user), 1000);
    } else {
      setTimeout(() => reject(`Unable to find user with id of ${id}.`), 1000);
    }
  });
};

Promise.all(flights.map(async flight => {
  const destlist = flight.data.destlist
    
  const updatedDestList = await Promise.all(destlist.map(async dest => {
    const user = await getUser(dest.userId)
      
    dest.name = user.name
      
    return dest
  }))
    
  flight.destlist = updatedDestList
    
  return flight
}))
.then(function(data) {
  prettyJSON(data);
})

function prettyJSON(obj) {
  console.log(JSON.stringify(obj, null, 2));
}
0 голосов
/ 20 сентября 2018

Поскольку функция getUser выполняется асинхронно, вы должны вернуть данные, когда она будет выполнена.Используйте async/await:

    return Promise.all(
      flt.data.destlist.map(async function (item) {
        await getUser(item.userId)
          .then(us => (item.name = us.name))
          .catch(err => console.log(err));
        return flt;
      }),
    );

Или, если вы не знакомы с async/await, вы можете напрямую ответить на звонок getUser:

Promise.all(
  flights.map(function (flt) {
    return Promise.all(
      flt.data.destlist.map(function (item) {
        return getUser(item.userId)
          .then(us => {
            item.name = us.name;
            return flt;
          })
          .catch(err => console.log(err));
      }),
    );
  }),
).then(function (data) {
  prettyJSON(data);
});

Таким образом, flt.data.destlist.map возвращаетмассив Promise, поэтому Promise.all будет ждать.

Также внешний prettyJSON не является необходимостью, и это сбивает с толку.

0 голосов
/ 20 сентября 2018

Поскольку вы не возвращаете Promise, но возвращаемое значение flt Promise.all не будет ждать загрузки данных.

getUser(item.userId)
        .then(us => (item.name = us.name))
        .catch(err => console.log(err));
return flt;

Сделать как return getUser(....

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...