首页 > 解决方案 > 修改并返回异步函数内的对象

问题描述

我想userTracker在异步 js 代码中修改一个对象 ()。运行函数 ( fetchUsers) 后,我希望在所述对象上有一个更新的字段。undefined但是我在修改函数中的对象后继续获得。我怎样才能做到这一点?

我的代码:

let userTracker = {
    counter : 0,
    data : []
}

function fetchUsers(userTracker) {
    let filter  = {"some" : "conditions"}
    User.find(filter).exec() // I am deliberately not calling the `limit()` function. I have a goal to achieve
    .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)
console.log(userTracker) // It logs `{}`. Accessing any field on the object shows `undefined`

运行函数后如何访问填充的userTracker对象fetchUsers?我想结束这样的事情

我想要达到的目标:

userTracker = {
    counter : 8,
    data : [
        user1, user2, user3, ...
    ]
}

我不擅长异步编程,非常感谢任何有关如何实现上述所需输出的帮助。

标签: javascriptnode.jsexpressmongooseasync-await

解决方案


@shivashriganesh-mahato的答案是正确的,但我想解释一下为什么您的原始代码不起作用。

每当您将回调传递给函数时,该函数可能会以以下两种方式之一调用它:(1) 同步或 (2) 异步。同步很容易理解;这意味着回调是在您将回调传递给的函数执行期间执行的。

异步非常不同。回调的执行被推迟,直到当前正在执行的所有同步代码完成。这包括您将回调传递给的函数、包含调用该函数的行的函数等等。回调至少会推迟到整个当前调用堆栈完成执行,之后可能还会更长。例如,当您发送网络请求并传递回调来处理响应时,回调不仅会延迟到调用堆栈清除之后,还会延迟到响应到达之后。从计算机的角度来看,它可能需要很长时间(即几毫秒)。

异步函数调用不会推送到调用堆栈的顶部。相反,它们被放在未来函数调用队列的末尾,每个函数调用都将启动一个自己的新调用堆栈。

您如何捕捉仅在当前调用堆栈展开后才发生的值更改?通过在它之后排队另一个异步函数调用。以下示例代码说明了简单超时的区别:

// 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)

Promise的.then方法也调用它的异步回调。好处then是它总是返回一个新的 Promise,所以你可以在第一个 Promise 完成后排队另一个异步回调,依此类推。因此,使您的代码工作的最小更改如下:

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))

推荐阅读