Обещания: цепные методы и работа с обоими возвращаемыми объектами?

#javascript #es6-promise

#javascript #es6-обещание

Вопрос:

У меня есть этот код:

 return (entity.User.getProjects(req.user.id, ....))
    .then((list) => {
        // party with list object!
        return {
            list: list
        }
    }
  

И я также хочу вызвать другой метод, entity.Tag.getAllForUser который возвращает tags список.

(ОБНОВЛЕНИЕ: мне нужно сделать это, используя только обещания — я не могу использовать async / await.)

Этот код не работает — он говорит, что оба list и tag не определены:

 return (entity.User.getProjects(req.user.id, ....))
    .then((list) => entity.Tag.getAllForUser(req.user.id))
    .then((list, tags) => {
        // party with both list and tags objects!
        return {
            list: list,
            tags: tags
        }
    }
  

Я также пытался связать второй вызов с первым:

 return (
    entity.User.getProjects(req.user.id, ....).then((list) => 
    entity.Tag.getAllForUser(req.user.id))
 ).then((list, tags) => {
    // party with both list and tags objects!
    return {
        list: list,
        tags: tags
    }
}
  

Но опять же, там говорится, что list не определено. Что работает?

Комментарии:

1. Почему у вас несколько возвратов?

2. @chevybow потому что я делаю это неправильно.

3. В вашем заголовке написано «цепные методы», но зачем вам вообще нужно связывание ?

4. @trincot Возможно, я этого не делаю! Мне нужно выполнить оба и использовать результаты обоих. Извините, что не выразился точнее.

Ответ №1:

Это зависит от того, являются ли ваши запросы независимыми или нет:

Получение нескольких разрешенных значений по независимым запросам:

Допустим, у меня есть getUsers() и getCities() , и оба независимы (вам не нужны пользователи, чтобы получать города и наоборот). Затем вы можете использовать Promise.all :

 Promise.all([getUsers(), getCities()])
.then(result => {
  // result here will be an array of two elements:
  // result[0] -> what getUsers resolves
  // result[1] -> what getCities resolves 
});
  

Получение нескольких разрешенных значений по зависимым запросам:

Если у вас есть, скажем, getUser() , который возвращает пользователя, а затем getCouple(user) , который возвращает человека, связанного с пользователем, а затем getHouse(user1, user2) , которому, оказывается, нужны оба из них, вы можете сделать следующее:

 const user = getUser();
const couple = user.then(u => getCouple(u)); // you can reuse a promise. This does not trigger then handler again, if
// the promise is settled will yield the settle value.
const house = user.then(u => {
  return couple.then(c => {
    return getHouse(u,c);
  });
});
  

Это становится намного приятнее с async / await:

 async function() {
  const user = await getUser();
  const couple = await getCouple(user);
  const house = await getHouse(user, couple);
}
  

Комментарии:

1. Спасибо! Это самое ясное объяснение, которое я где-либо видел 🙂

Ответ №2:

Лучшим решением здесь является Promise.all , которое принимает список обещаний и возвращает список разрешенных значений:

 return Promise.all([
  entity.User.getProjects(req.user.id),
  entity.Tag.getAllForUser(req.user.id);
])
  .then(([ list, tags ]) => {
    // Party!
    return { list, tags };
  });
  

Обязательная рекомендация использовать async и await :

 let [ list, tags ] = await Promise.all([
  entity.User.getProjects(req.user.id),
  entity.Tag.getAllForUser(req.user.id);
]);

return { list, tags };
  

Ответ №3:

Просто используйте Async/Await

 let list = await entity.User.getProjects(req.user.id, ....))
let tags = await entity.Tag.getAllForUser(req.user.id))

return {
        list: list,
        tags: tags
    }
}
  

Если вы не можете использовать Async/Await (хотя я рекомендую их использовать), вы можете использовать promise.all

 Promise.all([
   entity.User.getProjects(req.user.id),
   entity.Tag.getAllForUser(req.user.id);
 ]).then(([list,tag])=>{
   // do here whatever you want
})
  

Комментарии:

1. Спасибо! Это был бы самый простой способ, но, к сожалению, я не могу этого сделать, потому что кодовая база, в которой я работаю, не позволяет этого. (Обновил вопрос, чтобы прояснить это.)

2. @Richard вы можете использовать, promise.all хотя я все равно буду рекомендовать использовать asyc/await , что делает код более читаемым и простым в обслуживании.

Ответ №4:

Отвечая на мой собственный вопрос. Пожалуйста, не удаляйте, так как это может быть полезно для кого-то другого!

 return (entity.User.getProjects(req.user.id, ....))
    .then((list) => Promise.all([list, entity.Tag.getAllForUser(req.user.id)]))
    .then(([list, tags]) => {
        // party with both list and tags objects!
        return {
            list: list,
            tags: tags
        }
}
  

Комментарии:

1. Я рекомендую использовать Promise.all для одновременного выполнения обоих запросов! Ваше решение здесь будет излишне запускать вещи последовательно.