如何告诉Observable我的数组已完成

时间:2017-11-14 07:09:33

标签: javascript arrays rxjs observable

TLDR:如何判断Observed数组是否完成。例如,请参阅this jsBin

我是Observables的新手,所以我可能会从错误的角度来看待它。鉴于下面的代码or this jsBin,我应该做些什么来让用户的网站数组“完成”。

let firstUser = {
  name: 'Susan',
  sites: [
    {company: 'ABC Co', role: 'admin'},
    {company: 'XYZ Co', role: 'reader'}
  ]
};

user = new Rx.BehaviorSubject(firstUser);

function authorized(authRoles) {
    // check if the current user has one of the authorizedRoles roles
    return this.user
      .do(user => console.log("Checking user: ",JSON.stringify(user)))
      .flatMap( user => user.sites )
      .do(res => console.log("Mapped user roles: ",res))
      .first( site => authRoles.indexOf(site.role) !== -1 ) // only return when a role matches
      .do( res => console.log('First: ',res))
      .map( res => true)
}

// This one finds a match and completes
authorized(['writer','admin','reader']).subscribe(res =>{
  console.log("1: isAuthorized?: ",res);
}, err => {
  console.log("1: ERROR: User is not authorized!");
}, () => {
  console.log("1: Authorized check completed!");
});

// This one never completes
authorized(['writer','foo']).subscribe(res =>{
  console.log("2: isAuthorized?: ",res);
}, err => {
  console.log("2: ERROR: User is not authorized!");
}, () => {
  console.log("2: Authorized check completed!");
});

请注意,(第一个)[http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-first]如果没有找到错误会抛出错误,但只有在Observable完成时才会抛出错误。

如果找到匹配,上面的内容将正确返回并完成,但是如果没有匹配则它将永远不会完成或出错,因为user.sites数组永远不会完成。

有没有办法让阵列完整?如果我首先获取/订阅用户,我可以让它工作:

//
// Pretend that fetchedUser is fetched in a safer/more sane way

// fetch the user and set it
let fetchedUser;
user.subscribe(user => fetchedUser = user);

function authorized2(authRoles) {
    // check if the current user has one of the authorizedRoles roles
    return Rx.Observable.of(this.fetchedUser.sites)
      .do(sites => console.log("auth2: Checking users sites: ",sites))
      .flatMap( sites => sites )
      .do(res => console.log("Mapped user roles: ",res))
      .first( site => authRoles.indexOf(site.role) !== -1 ) // only return when a role matches
      .do( res => console.log('First: ',res))
      .map( res => true)
}

我觉得我错过了一个关键但又简单的步骤,可以使用纯粹的Observable来实现这一点。在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

Rx.Observable.of(this.fetchedUser.sites)将其参数转换为可观察序列,然后完成。这会触发.first运算符抛出异常。您永远不会完成this.user主题。您可以将其更改为this.user.take(1)甚至Rx.Observable.of(fetchedUser),如果您希望完成,请跳过将其设为行为主题。或者您可以将.first更改为.map,以便在用户未经授权时返回false。以下是使用take运算符的示例。

const user = Rx.Observable.create((o) => {
  window.setTimeout(() => {
    o.next({
      name: 'Susan',
      sites: [
        {company: 'ABC Co', role: 'admin'},
        {company: 'XYZ Co', role: 'reader'}
      ]
    });
  }, 1000);
});

function authorized(authRoles) {
    return user
      .take(1)
      .flatMap( user => user.sites )
      .first( site => authRoles.indexOf(site.role) !== -1 )
      .map( res => true);
}

authorized(['writer','admin','reader']).subscribe(res =>{
  console.log("1: isAuthorized?: ",res);
}, err => {
  console.log("1: ERROR: User is not authorized!");
}, () => {
  console.log("1: Authorized check completed!");
});

authorized(['writer','foo']).subscribe(res =>{
  console.log("2: isAuthorized?: ",res);
}, err => {
  console.log("2: ERROR: User is not authorized!");
}, () => {
  console.log("2: Authorized check completed!");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.min.js"></script>

看了你的例子后,我想知道为什么你要用RxJs来解决这个问题。 RxJs专门用于处理数据流,但您正在使用静态值。也许你的例子只是简化应用程序中实际发生的事情,但你可以在没有RxJs的情况下以同步的方式完成你的目标,而且会更加简单。这是一个例子:

function authorized(authRoles) {
    return firstUser.sites.some(x => authRoles.includes(x));
}