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

时间:2016-08-03 11:26:47

标签: javascript oop javascript-objects aurelia

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

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

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

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

我面临的问题是,在我使用用户服务提取用户之后,然后从我的一个自定义元素(存储在用户服务中)更新用户模型另一个自定义元素&# 39;对所述用户模型的引用不会更新。

我试图在JSFiddle中复制这个问题(简单的JS - 我在ES6中写这个)但是没有这样做,在小提琴中一切正常。

有相当多的代码,但我想听听你的意见,我可能做错了这件事发生了什么?

以下是我所拥有的要点:

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(如果我{{1},这会反映在UserService中} console.dir},但其他this.user' s CustomElement 更新。

顺便说一下:this.userPromise.resolve()的原因是将来会有服务器调用。

Tbh我对JS中的这种类型的编程很新,更多来自jQuery世界,尽管我基本上爱上了Aurelia这样的东西仍然让我很困惑,所以希望有一些洞察这里:))

1 个答案:

答案 0 :(得分:2)

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

一个建议 - 让您的代码更易于管理,减少异步......如果您按照以下方式构建代码:

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;
  }

  ...
}

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