Рефакторинг кода Express и не может определить область действия переменной - PullRequest
1 голос
/ 30 мая 2020

Надеюсь, это не глупый вопрос. У меня есть маршрут на домашнюю страницу, который загружает множество баз данных mon go, и я изначально использовал его l oop через базы данных mon go и добавил их в массив, который был отображен на веб-странице. Однако базы данных стали более сложными, и их необходимо заполнить, поэтому я больше не могу использовать al oop для выполнения sh этого, и мне потребовалось провести рефакторинг для получения баз данных по отдельности. Однако у меня, похоже, возникают проблемы с областями действия переменных, так как они всегда возвращаются как пустые вне функции .find. Мой исходный код был таким:

    const collections = [User, Ticket, Client, Job, Transaction];
    let endCollections = [];
    for (let i = 0; i < collections.length; i++){
        await collections[i].find({}, function(err, foundCollection){ 
            if (err) {
                console.log(err);
            } else {
                endCollections[i] = foundCollection;                
            }
        });
    }
    res.render("dashboard", {transactions: endCollections[4], clients: endCollections[2], tickets: endCollections[1], jobs: endCollections[3]});

И это сработало нормально. Но мне нужно заполнить отдельные базы данных, поэтому это больше не было полезно. Я переписал его для заполнения, но у меня проблемы с изменением глобальных переменных внутри функций. Вот новый код, который я пробую:

    let transactions = [],
    clients = [],
    jobs = [],
    tickets = [];

    await Transaction.find({}).populate("job").populate("client").populate("deposited_by_user").exec(function(err, foundTransactions){
        if(err){
            console.log(err)
        } else {                                        
            for (let i = 0; i < foundTransactions.length; i++){
                foundTransactions[i]["transaction_info"]["new_amount"] = numberWithCommas(foundTransactions[i]["transaction_info"]["amount"]);
            }
        }
        transactions = foundTransactions;
    });

    await Client.find({}).populate("transactions").populate("jobs").exec(function(err, foundClients){
        if(err){
            console.log(err)
        }
        clients = foundClients;
    });

    await Ticket.find({}).populate("created_by").populate("assigned_user").populate("completed_by_user").exec(function(err, foundTickets){
        if(err){
            console.log(err)
        }
        tickets = foundTickets;
    });

    await Job.find({}).populate("created_by").populate("client").populate("transactions").exec(function(err, foundJobs){
        if(err){
            console.log(err)
        }
        jobs = foundJobs;
    }); 

    res.render("dashboard", {transactions: transactions, clients: clients, tickets: tickets, jobs: jobs});

Например, если я console.log "jobs" сразу после строки jobs = foundJobs ;, он покажет, что массив заданий заполняется. Однако, если я console.log "jobs" прямо перед res.render, он показывает его как пустое. Учитывая, что глобальная переменная endCollections в моем исходном коде раньше казалась измененной внутри функций, я не уверен, почему мой новый код не работает так же, как все возвращается пустым. Я знаю, что почему-то здесь не так в области видимости переменной, но я не понимаю, как это сделать. Есть ли что-то очевидное, что мне не хватает? Спасибо.

1 Ответ

1 голос
/ 31 мая 2020

Вот теперь ответ, чтобы он не был похоронен в комментариях к сообщению.

После прочтения документации , я думаю, вам следует использовать await с пустым exe c () или используйте exe c (обратный вызов).

Что происходит, когда вы используете оба, - это то, что exe c (обратный вызов) видит, что вы передали обратный вызов, он асинхронно выполняет ваш запрос и добавляет обратный вызов к обещанию. затем обещание запроса, которое будет вызываться после выполнения обещания запроса. Затем он немедленно возвращается, но не возвращает обещание запроса, поскольку вы передали обратный вызов. Await просто ожидает нормального (вероятно, void / undefined) возврата функции, поэтому его удаление ничего не меняет.

После ожидания возврата из функции выполняется res.render и через некоторое время после этого , обещание, которое было создано в вызове exe c (обратный вызов), устанавливается, и переданный обратный вызов выполняется.

Итак, каков правильный способ исправить это? Я бы посоветовал вам глубже изучить async / awai, promises и документы, на которые я ссылался выше, и выяснить это самостоятельно, прежде чем читать дальше, но, поскольку решение довольно простое, я оставлю его здесь.

// your variable declarations
try {
    const foundTransactions = await Transaction.find({}).populate("job").populate("client").populate("deposited_by_user").exec();
    // your for loop
    transactions = foundTransactions;
    // same for the other calls
     tickets: tickets, jobs: jobs});
catch (e) {console.log(e);}
res.render("dashboard", {transactions: transactions, clients: clients,...
...