Лучший способ es6 получить результаты, основанные на имени, с помощью Promise.all

По умолчанию функция Promise.All([]) возвращает числовой индексный массив, содержащий результаты каждого обещания.

var promises = [];
promises.push(myFuncAsync1()); //returns 1
promises.push(myFuncAsync1()); //returns 2
Promise.all(promises).then((results)=>{
    //results = [0,1]
}

Каков наилучший способ ванильного возврата названного индекса результатов с помощью Promise.all()?

Я попытался использовать карту, но она возвращает результаты в массиве следующим образом: [key1, value1, key2, value2]

UPDATE:

Мои вопросы кажутся неясными, вот почему я не люблю упорядоченный индекс:

  • он дерьмовый, чтобы поддерживать: если вы добавите обещание в свой код, вам, возможно, придется переписать всю функцию результатов, потому что индекс может иметь изменения.
  • ужасно читать: results[42] (может быть исправлено с помощью jib-ответа ниже)
  • Невозможно использовать в динамическом контексте:
var promises = [];
if(...)
    promises.push(...);
else{
    [...].forEach(... => { 
        if(...)
            promises.push(...);
        else
            [...].forEach(... => {
                promises.push(...);
            });
    });
}
Promise.all(promises).then((resultsArr)=>{
    /*Here i am basically fucked without clear named results 
        that dont rely on promises' ordering in the array */
});

Ответ 1

Это что-то такое?

var promises = [];
promises.push(myFuncAsync1().then(r => {name : "func1", result : r}));
promises.push(myFuncAsync1().then(r => {name : "func2", result : r}));
Promise.all(promises).then(results => {
    var lookup = results.reduce((prev, curr) => {
        prev[curr.name] = curr.result;
        return prev;
    }, {});
    var firstResult = lookup["func1"];
    var secondResult = lookup["func2"];
}

Ответ 2

ES6 поддерживает деструктурирование, поэтому, если вы просто хотите назвать результаты, которые вы можете написать:

var myFuncAsync1 = () => Promise.resolve(1);
var myFuncAsync2 = () => Promise.resolve(2);

Promise.all([myFuncAsync1(), myFuncAsync2()])
  .then(([result1, result2]) => console.log(result1 +" and "+ result2)) //1 and 2
  .catch(e => console.error(e));

Ответ 3

что касается ответа @kragovip, причина, по которой вы хотите этого избежать, показана здесь:

https://medium.com/front-end-weekly/async-await-is-not-about-making-asynchronous-code-synchronous-ba5937a0c11e

"... очень легко привыкнуть ждать всех звонков в сети и ввода/вывода.

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

Плохой пример (НЕ СЛЕДУЕТ)

async function processData() {
  const data1 = await downloadFromService1();
  const data2 = await downloadFromService2();
  const data3 = await downloadFromService3();

  ...
}

"Также абсолютно не нужно ждать завершения первого запроса, поскольку ни один из других запросов не зависит от его результата.

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

Чтобы это исправить, мы можем использовать метод Promise.all(). Мы сохраняем Promises от вызовов асинхронных функций для переменных, объединяем их в массив и ожидаем их всех сразу ".

Вместо

async function processData() {
  const promise1 = downloadFromService1();
  const promise2 = downloadFromService2();
  const promise3 = downloadFromService3();

  const allResults = await Promise.all([promise1, promise2, promise3]);

Ответ 4

Отличным решением для этого является использование асинхронного ожидания. Не совсем ES6, как вы просили, но ES8! Но так как Babel полностью поддерживает это, мы начинаем:

Вы можете избежать использования только индекса массива, используя async/await следующим образом.

Эта async функция позволяет буквально останавливать код внутри нее, позволяя использовать ключевое слово await внутри функции, помещая его перед обещанием. Поскольку async функции await выполнения обещания, которое еще не выполнено, функция немедленно возвращает ожидающее обещание. Это возвращенное обещание разрешается, как только функция завершается позже. Функция возобновит работу только после разрешения ранее ожидаемого обещания, во время которого она преобразует весь оператор await Promise в возвращаемое значение этого обещания, позволяя вам поместить его в переменную. Это эффективно позволяет вам остановить ваш код, не блокируя поток. Это отличный способ для обработки асинхронных вещей в JavaScript в целом, потому что он делает ваш код более хронологическим и, следовательно, легче рассуждать о:

async function resolvePromiseObject(promiseObject) {
    await Promise.all(Object.values(promiseObject));

    const ret = {};

    for ([key, value] of Object.entries(promiseObject)) {
        // All these resolve instantly due to the previous await
        ret[key] = await value;
    };

    return ret;
}

Как и все, что выше ES5: пожалуйста, убедитесь, что Babel настроен правильно, чтобы пользователи в старых браузерах могли запускать ваш код без проблем. Вы можете заставить асинхронное ожидание работать безупречно даже на IE11, при условии, что ваша конфигурация Babel верна.