Использование «карты» с обещаниями возвращает упорядоченные и неупорядоченные результаты - PullRequest
0 голосов
/ 01 декабря 2018

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

const Axios = require('axios');
const baseURL = 'https://jsonplaceholder.typicode.com';

async function main() {
    const posts = await Axios(`${baseURL}/posts`);
    const users = await Promise.all(posts.data.map( async (post, index) => {
        let d = await Axios(`${baseURL}/users/${post.userId}`);
        return d.data.name;
    }))

    users.map( (user, index) => {
        console.log( `${index}. ${user}` );
    });
}

И выводит результат в следующем порядке:

1. Patricia
2. Glenna
3. Nicholas
4. Kurtis
5. Chelsey

Все в порядке, но ... Если я делаю:

async function main() {
    const posts = await Axios(`${baseURL}/posts`);
    await Promise.all(posts.data.map( async (post, index) => {
        let d = await Axios(`${baseURL}/users/${post.userId}`);
        console.log( `${index}. ${d.data.name}` );
    }))
}

console.log внутри map печатает список неупорядоченных ...

2. Glenna
4. Kurtis
5. Chelsey
1. Patricia
3. Nicholas

Мой вопрос:

Почему в первый код map возвращает список упорядоченный , а во второй console.log внутри map печатает список неупорядоченный

Ответы [ 4 ]

0 голосов
/ 01 декабря 2018

Поскольку Promise.all выполняет обещания параллельно и является асинхронным, в то время как .map блокирует и выполняет с порядком, он не завершится, пока не выполнит итерацию по всем элементам.Это похоже на цикл for-each.

Если вы хотите добиться порядка, либо я предлагаю вам использовать Bluebird.each (библиотека), либо что-то вроде этого:

const promiseEach = promises => {
  const results = [];

  return promises
    .reduce((acc, val, idx) => acc.then(_ => ((idx > 0 && results.push(_)), val)), Promise.resolve())
    .then(_ => [...results, _]);
}

const a1 = Promise.resolve(1);
const a2 = Promise.resolve(2);
const a3 = Promise.resolve(3);

const d1 = new Promise((resolve, reject) => { setTimeout(() => resolve(1), 3000); }); // resolves after 3 seconds.
const d2 = new Promise((resolve, reject) => { setTimeout(() => resolve(2), 2000); }); // resolves after 2 seconds.
const d3 = new Promise((resolve, reject) => { setTimeout(() => resolve(3), 1000); }); // resolves after 1 seconds.

// this will respect orderings, before first promise is not resolved, does not goes to next one.
promiseEach([a1, a2, a3, d1, d2, d3]).then(console.log);

и передатьсопоставьте с promiseEach функцией, и они будут упорядочены.

0 голосов
/ 01 декабря 2018

Когда вы используете Promise.all (запросы), все запросы выполняются параллельно, поэтому вы не можете знать, что заканчивается раньше другого.

В первом коде у вас уже был результат в порядкемассив запросов.Но во втором, console.log находится в порядке ответов.

0 голосов
/ 01 декабря 2018

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

Однако, если вы выведите значения , как только их обещания разрешат , то вышеизложенное, конечно, не повлияет на ваш вывод - теперь оно будет упорядочено в порядке, в котором разрешаются отдельные обещания.

Простой пример:

Допустим, есть три обещания p1, p2, p3, которые разрешаются в 1, 2 и 3. Но второе обещание разрешится раньше, чемдва других.

Promise.all вызывается с [p1, p2, p3].Он возвращает новое обещание, которое в конечном итоге разрешится на [1, 2, 3].В то время, когда не все обещания разрешены, вы можете представить, что внутренний массив развивается следующим образом:

  • p2 разрешается.Promise.all внутренне хранит [undefined, 2, undefined]
  • p1 разрешает.Promise.all внутренне хранит [1, 2, undefined]
  • p3 разрешает.Promise.all также разрешается со значением [1, 2, 3]

Здесь вы можете видеть, что первый код будет выводить 2, 1, 3, а второй - 1, 2, 3

0 голосов
/ 01 декабря 2018

Поскольку, если вы используете асинхронный код, не имеет значения, в каком порядке вы «запустили» запросы, он только подсчитывает, сколько времени займет ответ.

Таким образом, ваш результат будет упорядочен по тому, как завершены ваши запросы,так что если ваш запрос на x завершился первым, даже если вы его запустили последним, он все равно будет на первой позиции вашего результата

Функция карты «блокирует», что означает, что второй запрос сработает послепервый закончен и т. д.

вот пример: https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/

...