【问题标题】:How do I tell an Observable that my array is complete如何告诉 Observable 我的数组是完整的
【发布时间】:2017-11-14 07:09:33
【问题描述】:

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!");
});

请注意,(first)[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)
}

我觉得我错过了使用纯 Observables 让它工作的关键但简单的步骤。提前感谢您的帮助!

【问题讨论】:

标签: javascript arrays rxjs observable


【解决方案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));
}

【讨论】:

  • 我介绍了在 JSBin 中使用 Rx.Observable.of,但我想我真正想知道的是,我能否知道或以某种方式告诉它“完成”给定的 Observable 数组?我确实知道我给出的示例并不是真正应该如何使用它们,但它确实代表了与实际用例所需的类似逻辑。正如所写,你答案的最后一部分是正确的。
  • @jrose .take(1) 将在一项流过它后完成流。你想在什么条件下完成?
  • 我希望它在所有“站点”都流过之后完成。
  • @jrose 只有一项流经流直到 flatMap。因此,如果您在平面图之前对静态值使用of 运算符或在可观察对象上使用take,那么在所有站点都流过之后完成。
  • @jrose 我添加了一个使用take的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-02
  • 2020-07-27
相关资源
最近更新 更多