Один из вариантов - использовать Promise
цепочку. collection.find({}).toArray()
может либо принимать функцию обратного вызова, либо возвращать обещание, поэтому вы можете связывать вызовы с помощью .then()
collection.find({}).toArray() // returns the 1st promise
.then( items => {
console.log('All items', items);
return collection.find({ name: /^S/ }).toArray(); //return another promise
})
.then( items => {
console.log("All items with field 'name' beginning with 'S'", items);
client.close(); // Last promise in the chain closes the database
);
Конечно, такое последовательное соединение делает код более синхронным. Это полезно, когда следующий вызов в цепочке относится к предыдущему, например, получение идентификатора пользователя в первом, а затем поиск сведений о пользователе в следующем.
Несколько несвязанных запросов должны выполняться параллельно (asyn c), а когда все результаты вернутся, избавиться от соединения с базой данных. Это можно сделать, например, отслеживая каждый вызов в массиве или счетчике.
const totalQueries = 3;
let completedQueries = 0;
collection.find({}).toArray()
.then( items => {
console.log('All items', items);
dispose(); // Increments the counter and closes the connection if total reached
})
collection.find({ name: /^S/ }).toArray()
.then( items => {
console.log("All items with field 'name' beginning with 'S'", items);
dispose(); // Increments the counter and closes the connection if total reached
);
collection.find({ age: 55 }).toArray()
.then( items => {
console.log("All items with field 'age' with value '55'", items);
dispose(); // Increments the counter and closes the connection if total reached
);
function dispose(){
if (++completedQueries >= totalQueries){
client.close();
}
}
У вас есть 3 запроса. Когда каждый вызывает dispose()
, счетчик увеличивается. Когда они все вызовут dispose()
, последний также закроет соединение.
Async / Await должно сделать это еще проще, поскольку они разворачивают результат Promise
из функции then
.
async function test(){
const allItems = await collection.find({}).toArray();
const namesBeginningWithS = await collection.find({ name: /^S/ }).toArray();
const fiftyFiveYearOlds = await collection.find({ age: 55 }).toArray();
client.close();
}
test();
Ниже приведен пример того, как Async / Await может закончиться создание асин c кода, который ведет себя последовательно и работает неэффективно, ожидая завершения одной асин c функции перед вызовом следующей, когда идеальным сценарием является немедленный вызов их всех и ожидание их завершения.
let counter = 0;
function doSomethingAsync(id, start) {
return new Promise(resolve => {
setTimeout(() => {
counter++;
const stop = new Date();
const runningTime = getSeconds(start, stop);
resolve(`result${id} completed in ${runningTime} seconds`);
}, 2000);
});
}
function getSeconds(start, stop) {
return (stop - start) / 1000;
}
async function test() {
console.log('Awaiting 3 Async calls');
console.log(`Counter before execution: ${counter}`);
const start = new Date();
let callStart = new Date();
const result1 = await doSomethingAsync(1, callStart);
callStart = new Date();
const result2 = await doSomethingAsync(2, callStart);
callStart = new Date();
const result3 = await doSomethingAsync(3, callStart);
const stop = new Date();
console.log(result1, result2, result3);
console.log(`Counter after all ran: ${counter}`);
console.log(`Total time to run: ${getSeconds(start, stop)}`);
}
test();
Примечание. Ожидание, как в примере выше, снова делает последовательность вызовов. Если на запуск каждой из них уходит 2 секунды, функция завершится за 6 секунд.
Объединяя лучшее из всех миров, вы захотите использовать Async / Await при одновременном запуске всех вызовов. К счастью, Promise
имеет метод для этого, поэтому test()
можно записать так: -
async function test(){
let [allItems, namesBeginningWithS, fiftyFiveYearOlds] = await Promise.all([
collection.find({}).toArray(),
collection.find({ name: /^S/ }).toArray(),
collection.find({ age: 55 }).toArray()
]);
client.close();
}
Вот рабочий пример, демонстрирующий разницу в производительности: -
let counter = 0;
function doSomethingAsync(id, start) {
return new Promise(resolve => {
setTimeout(() => {
counter++;
const stop = new Date();
const runningTime = getSeconds(start, stop);
resolve(`result${id} completed in ${runningTime} seconds`);
}, 2000);
});
}
function getSeconds(start, stop) {
return (stop - start) / 1000;
}
async function test() {
console.log('Awaiting 3 Async calls');
console.log(`Counter before execution: ${counter}`);
const start = new Date();
const [result1, result2, result3] = await Promise.all([
doSomethingAsync(1, new Date()),
doSomethingAsync(2, new Date()),
doSomethingAsync(3, new Date())
]);
const stop = new Date();
console.log(result1, result2, result3);
console.log(`Counter after all ran: ${counter}`);
console.log(`Total time to run: ${getSeconds(start, stop)}`);
}
test();