Страницы

Поиск по вопросам

среда, 29 января 2020 г.

Асинхронный map [дубликат]

#nodejs #async_await #backend


        
             
                
                    
                        
                            На этот вопрос уже даны ответы здесь:
                            
                        
                    
                
                        
                            Как выполнить последовательно несколько асинхронных фунций
в Javascript без коллбэков?
                                
                                    (3 ответа)
                                
                        
                                Закрыт 1 год назад.
            
                    
Пишу бекенд на node (v 8.11.4)

Сервер общается с vk api. У vk есть ограничение - 5 запросов с секунду.

Чтобы не уперется в ограничение было решено сделать функцию sleep:

export default (ms) => {
    return new Promise(resolve => setTimeout(resolve, ms));
};


Далее есть мой метод (туда импортирую функцию sleep):

app.post(path, (req, res) => {
    [1,2,3].map(async item => {
        await sleep(1000);
        console.log(item);
    })
})


Здесь я ожидаю что console.log будет срабатывать раз в секунду. Но этого не происходит.
Проходит 1 секунда и console.log выводится 3 раза.
    


Ответы

Ответ 1



Все дело в том что этот код: [1,2,3].map(async item => { await sleep(1000); console.log(item); }) Тоже самое что и этот let foo = async item => { await sleep(1000); console.log(item); } foo(); foo(); foo(); Все три функции вызываются сразу. Каждая ждет по секунде и затем одна за другой выводят item в консоль. Так как начинают ждать они одновременно, то и заканчивают тоже, поэтому вы видите что сообщения выводятся сразу все. Можно сделать так: const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; const foo = async (item, i) => { setTimeout(() => { return console.log(item); }, 1000 * i); // 1000 - это ваша задержка между вызовами } numbers.map(foo); Можно ставить устанавливать задержку после каждого вызова: const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; const delayLoop = (array, delay) => { let i = 0; const loop = () => { setTimeout(() => { console.log(numbers[i]); if (++i < numbers.length) { loop(); } }, delay); }; loop(); } delayLoop(numbers, 1000); Можно сделать пример выше более универсальным, добавив callback: const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; const delayLoop = (array, delay, handler) => { let i = 0; const loop = () => { setTimeout(() => { handler(numbers[i]); if (++i < numbers.length) { loop(); } }, delay); }; loop(); } const count = (value) => { console.log(`counter: ${value}`); } delayLoop(numbers, 1000, count);

Ответ 2



Если я правильно понял инужно выводитьв консоль значения из массива с заданным интервалом, то можно сделать так - const sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); }; const array = [1, 2, 3]; array.reduce(async(result, current) => result.then(() => sleep(1000).then(() => console.log(current))), Promise.resolve());

Ответ 3



Возможно, такие циклы проще делать с помощью for..of циклов: app.post(path, async (req, res) => { for (const item of [1,2,3]) { await sleep(1000); console.log(item); }) })

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

Отправить комментарий