Ответ @ shivashrigane sh -mahato правильный, но я хотел бы объяснить, почему ваш исходный код не работает.
Всякий раз, когда вы передаете обратный вызов функция, эта функция может вызывать ее одним из двух способов: (1) syn c или (2) asyn c. Син c легко понять; это означает, что обратный вызов выполняется во время выполнения функции, которой вы передали обратный вызов.
Asyn c очень отличается. Выполнение обратного вызова откладывается до тех пор, пока не будет завершен весь код syn c, который выполняется в данный момент. Это включает в себя функцию, которой вы передали обратный вызов, функцию, которая включает в себя строку, в которой вы вызываете эту функцию, и так далее. Обратный вызов откладывается по крайней мере до тех пор, пока не завершится выполнение всего текущего стека вызовов, и, возможно, еще дольше после этого. Например, когда вы отправляете сетевой запрос и передаете обратный вызов для обработки ответа, обратный вызов не только откладывается до тех пор, пока не очищается стек вызовов, но и до тех пор, пока не будет получен ответ. С точки зрения компьютера это может занять вечность (т. Е. Несколько миллисекунд).
Asyn c вызовы функций не помещаются поверх стека вызовов. Вместо этого они помещаются в конец очереди будущих вызовов функций, каждый из которых запускает новый собственный стек вызовов.
Как отловить изменение значения, которое происходит только после текущего стека вызовов раскручивается? В очереди другой асин c вызов функции после it. Следующий пример кода иллюстрирует разницу с простыми тайм-аутами:
// sync
let count = 0;
function increment() { ++count; }
function invokesCallbackSync(callback) {
callback();
}
invokesCallbackSync(increment);
console.log(count); // 1
// async
count = 0;
function invokesCallbackAsync(callback) {
setTimeout(callback);
}
invokesCallbackAsync(increment);
console.log(count); // 0
setTimeout(() => console.log(count)); // 1 (eventually)
Метод обещания .then
также вызывает его асинхронный обратный вызов c. Приятной особенностью then
является то, что он всегда возвращает новое обещание, поэтому вы можете поставить в очередь еще один асинхронный обратный вызов c после завершения первого обещания и так далее. Таким образом, минимальное изменение для обеспечения работы вашего кода выглядит следующим образом:
let userTracker = {
counter : 0,
data : []
}
function fetchUsers(userTracker) {
let filter = {"some" : "conditions"}
return User.find(filter).exec()
.then( (users ) => {
return users.forEach((user) => {
if (userTracker.counter < 20) {
userTracker.data.push(user)
userTracker.counter += 1
} else {
return
}
})
})
.catch(err => {
console.log(err)
})
}
fetchUsers(userTracker).then(() => console.log(userTracker))