在异步函数调用过程中,当对象的属性值发生变化时,JavaScript中的对象属性值会发生什么变化

What happens to property values on an object in JavaScript when its property values change during asynchronous function calls?

本文关键字:变化 对象 属性 JavaScript 什么 异步 过程中 函数调用      更新时间:2023-09-26

我想知道传递给异步函数(如数据库保存)的javascript对象会发生什么,然后立即更改其属性值。

我对此感兴趣的原因是异步代码需要很长时间才能完成,因此等待它回调的时间将比我想要的响应时间更长。

取以下代码:

function asyncDatabaseSave(user) {
// Save the user asynchronously in the database   
// Do things that take a lot of time before calling back
}
app.get(function (req, res) {
    // In real code user is an object that gets passed in.
    user = {cart: [1, 2, 3]};
    // What is the value of user.cart going to be when it reaches the databaseSave call?
    // At the time of the function call, user.cart has options but it is set to null immediately after
    asyncDatabaseSave(user);
    user.cart = null;
    res.json(user);
})

我认为,确保用户对象是用cart而不是null保存的,然后清除它的"正确"方法是将回调传递到asyncDatabaseSave,在保存后将其设置为null

不过,我有兴趣尽快致电res.json。我也试验过这个代码:

app.get(function (req, res) {
    var items = user.cart;
    user.cart = null;
    res.json(user);
    asyncDatabaseSave(user, items);
})

通过这种方式,items被存储为一个单独的var,并被传递到一个稍微修改过的数据库保存函数中。

当调用asyncDatabaseSave,然后立即将其设置为null时,user.cart会发生什么?

如果我试图用购物车保存user,但也将购物车设置为nulluser返回,那么最好的方法是什么?

当调用asyncDatabaseSave,然后它之后立即设置为null?

您必须知道异步数据库调用中实际发生了什么,才能知道在进行调用后立即修改传入的对象是否安全。在许多情况下,user对象的操作部分已经被复制到本地代码中,并在asyncDatabaseSave()返回之前发送到数据库,因此进一步修改user对象根本不会影响异步调用。

但是,在某些情况下,你不能假设这一点,特别是如果asyncDatabaseSave()实际上由几个异步调用组成,并且在它们之间运行一些Javascript(例如打开数据库,然后写入数据库。在这些情况下,修改你所在的user对象可能会影响事情。

如果我试图用购物车保存用户,但也用返回用户cart设置为null,最好的方法是什么?

因此,为了安全起见,不要在asyncDatabaseSave(user)之后立即修改user对象。

如果您真的只是想尽快调用res.json(user),那么您只需制作user对象的副本,修改该副本,然后在两个异步操作中使用每个单独的副本。这是在所有情况下都有效的一般答案,也是安全的做事方式。

如果asyncDatabaseSave()中不需要整个cart对象,那么只挑选需要的部分并传递这些部分(就像您上次的建议一样),就可以在之后自由分配cart属性,而不会有任何风险。您必须小心不要访问cart对象并更改cart对象中的对象,因为这可能会更改您传递给asyncDatabaseSave()的相同对象,但您当然可以为cart对象分配属性,如果您不传递cart对象,这不会影响asyncDatabaseSave()

这里有一个简单的例子来展示假设您可以修改传入的对象是如何不安全的:

function someAsyncSave(u) {
   setTimeout(function() {
       log(u.name)
   }, 50);
}
var user = {name: "Joe"};
someAsyncSave(user);
user.name = "Alice";
<script src="http://files.the-friend-family.com/log.js"></script>

运行代码段。它将记录"Alice",即使调用someAsyncSave()时属性为"Joe"。

尽管user对象在传递给someAsyncSave()时具有user.name = "Joe",但当someAsyncSave()实际使用该属性时,它已经被外部代码更改。