对对象的引用以某种方式丢失

Reference to Object is lost somehow

我正在使用 Aurelia 框架构建一个相当高级的应用程序,该框架使用模型、服务和自定义元素。

我有一个包含用户名、电子邮件等的用户模型以及一个 bool isLoggedIn。

我有一个将用户存储在 localStorage 中的用户服务,允许您更新用户数据等等。

我终于有了一些自定义元素,它们使用用户服务获取当前用户并根据用户是否登录显示 UI。

我面临的问题是,在我使用用户服务获取用户,然后从我的一个自定义元素(存储在用户服务中)更新用户模型后,另一个自定义元素引用了上述内容用户模型不会更新。

我试图在 JSFiddle 中复制这个问题(在普通 JS 中——我在 ES6 中写这个)但是没有这样做,在 fiddle 中一切正常。

有很多代码,但我想听听您的意见,我可能做错了什么才会发生这种情况?

这是我的要点:

user.model.js

export class User {
    username = '';
    isLoggedIn = false;

    constructor (data) {
        Object.assign(this, data);
    }
}

user.service.js

import { User } from 'user.model';

export class UserService {
    constructor () {
        this.user = null;
    }

    getUser () {
        // User is cached
        if (this.user) {
            return Promise.resolve(this.user);
        }

        // Check if we have localStorage
        var user = window.localStorage.getItem('user');

        if (user) {
            this.user = new User(JSON.parse(user));

            return Promise.resolve(this.user);
        }

        // No user - create new
        this.user = new User();

        return Promise.resolve(this.user);
    }

    saveUser () {
        this.getUser().then(() => {
            window.localStorage.setItem('user', JSON.stringify(this.user));
        });
    }

    updateUser (user) {
        this.getUser().then(() => {
            Object.assign(this.user, user);

            this.saveUser();
        });
    }

    login () {
        this.updateUser({
            isLoggedIn: true
        });

        return Promise.resolve(true);
    }
}

自定义-element.js

import { inject } from 'aurelia-framework';

import { UserService } from 'user.service';

@inject (UserService)
export class CustomElement {
    constructor (userService) {
        this.userService = userService;
    }

    attached () {
        this.userService.getUser().then(user => {
            this.user = user;

            console.log('Fetched user:');
            console.dir(this.user);

            console.log('Same?');
            console.dir(this.user === user); // this is true
        });

        // At some point another custom element fires the UserService.login() method
        // Here we check that our reference to the user also updates

        setInterval(() => {
            console.log('Is user logged in?');
            console.dir(this.user.isLoggedIn); // This is always false - even after UserService.login() has been called and UserService.user is updated (if I console.dir this.user inside UserService it is indeed updated)

            // Grab a new version of UserService.user
            this.userService.getUser().then(user => {
                console.log('Fetched new user, is new user and our user same?');
                console.dir(this.user === user); // false :/ the new user fetched here actually has isLoggedIn === true but our this.user does not...
            });
        }, 2000);
    }
}

如评论中所述,在某一时刻,另一个自定义元素运行 UserService.login(),将 UserService.user.isLoggedIn 更改为 true(这反映在 UserService 中,如果我 console.dirthis.user) 但另一个 CustomElementthis.user 更新。

顺便说一句:UserService.getUser()中的Promise.resolve()的原因是将来会有服务器调用。

老实说,我对 JS 中的这种类型的编程很陌生,更多来自 jQuery 世界,尽管我基本上爱上了像这样的 Aurelia 东西,但我仍然很困惑所以希望在这里获得一些见解:)

查看您提供的代码,我看不出什么会导致您所描述的行为。

一个建议 - 让您的代码更易于管理,减少异步...如果您将其结构化如下:

user.js

export class User {
  loggedIn = false;
  name = 'Anonymous';
}

用户-store.js

@inject(User)
export class UserStore {
  constructor(user) {
    this.user = user;
  }

  load() {
    const serializedUser = localStorage.getItem('user');
    if (!info) {
      return;
    }
    const storageUser = JSON.parse(serializedUser);
    this.user.loggedIn = storageUser.loggedIn;
    this.user.name = storageUser.name;
  }

  save() {
    const serializedUser = JSON.stringify(this.user);
    localStorage.setItem('user', serializedUser);
  }
}

auth-service.js

@inject(User, UserStore)
export class AuthService {
  constructor(user, store) {
    this.user = user;
    this.store = store;
  }

  login(username, password) {
    return fetch('https://api.megacorp.com/login', { method: 'POST' ... })
      .then(result => {
        this.user.loggedIn = true;
        this.user.name = result.name;
        this.store.save();
      });
  }
}

自定义-element.js

@inject(User)
export class CustomElement {
  constructor(user) {
    this.user = user;
  }

  ...
}

好处是您的自定义元素永远不需要依赖异步的东西。他们只是获取应用程序的 User 实例,其属性可能会更改但将始终保持相同的实例。