Zonor
@Zonor
Начинающий веб программист

Как на node js быстрее выполнить задачу множественных запросов и записи в базу асинхронно?

Предположим что есть 20 эндпоинтов на стороннем API 'example.com/api/Something1', 'example.com/api/Something2' и тд.
Необходимо сделать запрос на эти 20 эндпоинтов, каждый эндпоинт возвращает 100 id.
Далее необходимо сделать 2 запроса на другой API example.com/api/getSomething1/id и example.com/api/getSomething2/id для каждого полученного id.
после чего записать в базу последовательно getSomething1 и getSomething2 - который будет привязан к getSomething1.
2 * 100 * 20 = 4000. Получается около 4000 запросов.
Данные нужно держать актуальными каждые 3-5 секунд, в зависимости от того, как быстро отработает приложение. Чем быстрее тем лучше.

import axios from "axios";
import {Post, Todo} from "./models/Relations.js";

async function main() {
    const begin = performance.now();
    console.log('BEGIN ', begin)
    const skip = [0, 20, /*40,60,80 */]

    const idsPromises = skip.map(sk => axios.get(`https://dummyjson.com/users?limit=20&skip=${sk}&select=firstName,age`))
    const idsResponses = await Promise.all(idsPromises)

    const postsAndTodosPromises = idsResponses.map(response => response.data.users.map(async user => {
        return Promise.all([
            axios.get(`https://dummyjson.com/users/${user.id}/posts?select=id,title&limit=1`),
            axios.get(`https://dummyjson.com/users/${user.id}/todos?select=id,todo&limit=1`)
        ])
    }))
    const PostAndTodosResponsesPromises = [].concat(...postsAndTodosPromises)
    const PostAndTodosResponses = await Promise.all(PostAndTodosResponsesPromises.flat())
    const savingPromises = PostAndTodosResponses.map(PostAndTodosResponse => saveData(PostAndTodosResponse[0], PostAndTodosResponse[1]))
    Promise.all(savingPromises).then(pid => {
        const end = performance.now();
        console.log('END ', end)
        const timeTaken_ms = end - begin;
        console.log('Time ', timeTaken_ms)
        console.log('SAVED ', pid)
    })
}

async function saveData(post, todo) {
    if (post.data.posts.length > 0) {
        const savedPost = await Post.upsert(post.data.posts[0])
        return post.data.posts[0].id
    }
    if (todo.data.todos.length > 0) {
        const savedTodo = await Todo.upsert(todo.data.todos[0])
        return todo.data.todos[0].id
    }
    return false
}

main()

Код абстрактный, чтобы было понятнее задачу. И меня терзают мысли, будет ли это наиболее быстрым вариантом, или есть варианты быстрее? Например пока мы ждем выполнения всех промисов - нам уже поступают ответы, и мы могли бы их начать обрабатывать.
Например вызвать сбор ID для первого URL, когда он выполнится - сделать 2 промиса для Something1 и Something2 и подождать их, потом отправить на запись в базу. Что то вроде такого
import axios from "axios";
import {Post, Todo} from "./models/Relations.js";


// 'https://dummyjson.com/users?limit=5&skip=10&select=firstName,age' получить юзеров  0-20 20-40 40-60 60-80 80-100
// 'https://dummyjson.com/users/5/posts получить посты юзеров
// 'https://dummyjson.com/users/5/todos' получить тудушки юзеров

function main(){
    const skip = [ 0,20,/*40,60,80 */]

    for (const k in skip){
        getIds(skip[k])
    }
}

async function getIds(skip) {
    const begin = performance.now();
    console.log('BEGIN ' + skip, begin)
    const ids = await axios.get(`https://dummyjson.com/users?limit=20&skip=${skip}&select=firstName,age`)
    const idsPromises = ids.data.users.map(async user => {
        const postPromise = axios.get(`https://dummyjson.com/users/${user.id}/posts?select=id,title&limit=1`)
        const todoPromise = axios.get(`https://dummyjson.com/users/${user.id}/todos?select=id,todo&limit=1`)

        const post = await postPromise
        if (post.data.posts.length > 0){
            const savedPost = await Post.upsert(post.data.posts[0])
        }
        const todo = await todoPromise
        if (todo.data.todos.length > 0) {
            const savedTodo = await Todo.upsert(todo.data.todos[0])
        }
    })
    Promise.all(idsPromises).then(() => {
        const end = performance.now();
        console.log('END ' + skip, end)
        const timeTaken_ms = end - begin;
        console.log('Time ' + skip, timeTaken_ms)
    })
}


main()

Как сделать лучше для максимального быстродействия? Доступ к API будет только на следующей неделе, поэтому тесты не могу провести. Да и не для тестов этот API. Попробую конечно на фейковых API сделать что то подобное, но знать бы еще как правильно замерять время выполнения асинхронщины
P.S. Вроде затестил, но не знаю правильно ли. И судя по тестам - разницы нет. Может быть еще какие то варианты есть чтобы ускорить? Может подключить воркеров !?
1 вариант

BEGIN  378.86680006980896
END  1985.807000041008
Time 0,20 1606.940199971199

2 вариант

BEGIN 0 385.55189990997314
BEGIN 20 418.53279995918274
END 20 1935.0159999132156
Time 20 1516.483199954033
END 0 1937.396399974823
Time 0 1551.8445000648499
  • Вопрос задан
  • 120 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы