Javascript RxJS序列等价于promise.then()?

Javascript RxJS序列等价于promise.then()?,javascript,rxjs,Javascript,Rxjs,我曾经开发了很多有希望的东西,现在我要搬到RxJS。RxJS的文档没有提供一个关于如何从承诺链转移到观察者序列的非常清晰的示例 例如,我通常编写包含多个步骤的承诺链,如 // a function that returns a promise getPromise() .then(function(result) { // do something }) .then(function(result) { // do something }) .then(function(result

我曾经开发了很多有希望的东西,现在我要搬到RxJS。RxJS的文档没有提供一个关于如何从承诺链转移到观察者序列的非常清晰的示例

例如,我通常编写包含多个步骤的承诺链,如

// a function that returns a promise
getPromise()
.then(function(result) {
   // do something
})
.then(function(result) {
   // do something
})
.then(function(result) {
   // do something
})
.catch(function(err) {
    // handle error
});
我应该如何用RxJS风格重写这个承诺链呢?

对于数据流(相当于
然后
):

承诺可以转化为可观察的承诺

一些promise操作符具有直接翻译。例如
RSVP.all
,或
jQuery.when
可以替换为
Rx.Observable.forkJoin

请记住,您有一组运算符,允许异步转换数据,并执行无法执行或很难执行的任务。Rxjs通过异步数据序列(序列即超过1个异步值)显示其所有能力

对于错误管理,主题稍微复杂一点

  • 也有很多人和运营商
  • retryWhen
    也有助于在出现错误时重复序列
  • 您还可以使用
    onError
    功能处理订户本身的错误
要获得精确的语义,请更深入地查看您可以在web上找到的文档和示例,或者在此处提出特定的问题


这无疑是深入使用Rxjs进行错误管理的良好起点:

一个更现代的替代方案:

import {from as fromPromise} from 'rxjs';
import {catchError, flatMap} from 'rxjs/operators';

fromPromise(...).pipe(
   flatMap(result => {
       // do something
   }),
   flatMap(result => {
       // do something
   }),
   flatMap(result => {
       // do something
   }),
   catchError(error => {
       // handle error
   })
)

还要注意,要使所有这些都起作用,您需要在某个地方订阅这个管道
可观察的
,但我假设它是在应用程序的其他部分处理的。

如果
getPromise
函数位于流管道的中间,您应该简单地将它包装成一个函数
mergeMap
switchMap
concatMap
(通常
mergeMap
):

如果要使用
getPromise()
启动流,请将其包装到
from
函数中:

import {from} from 'rxjs';

from(getPromise()).pipe(
   filter(...)
   map(...)
).subscribe(...);

据我所知,如果在flatMap中返回结果,它会将其转换为数组,即使返回字符串也是如此


但是如果你返回一个可观察的,那个可观察的可以返回一个字符串

如果我理解正确,您的意思是使用这些值,在这种情况下,您使用sbuscribe,即

const arrObservable = from([1,2,3,4,5,6,7,8]);
arrObservable.subscribe(number => console.log(num) );
此外,您还可以使用toPromise()将可观察对象转换为承诺,如图所示:

arrObservable.toPromise().then()

使用RxJs 6于2019年5月更新

同意上面提供的答案,希望使用rxjsv6添加一个带有一些玩具数据和简单承诺(带有setTimeout)的具体示例,以增加清晰度

只需将传递的id(当前硬编码为
1
)更新为不存在的内容即可执行错误处理逻辑。重要的是,还要注意将
catchError
消息一起使用

import { from as fromPromise, of } from "rxjs";
import { catchError, flatMap, tap } from "rxjs/operators";

const posts = [
  { title: "I love JavaScript", author: "Wes Bos", id: 1 },
  { title: "CSS!", author: "Chris Coyier", id: 2 },
  { title: "Dev tools tricks", author: "Addy Osmani", id: 3 }
];

const authors = [
  { name: "Wes Bos", twitter: "@wesbos", bio: "Canadian Developer" },
  {
    name: "Chris Coyier",
    twitter: "@chriscoyier",
    bio: "CSS Tricks and CodePen"
  },
  { name: "Addy Osmani", twitter: "@addyosmani", bio: "Googler" }
];

function getPostById(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const post = posts.find(post => post.id === id);
      if (post) {
        console.log("ok, post found!");
        resolve(post);
      } else {
        reject(Error("Post not found!"));
      }
    }, 200);
  });
}

function hydrateAuthor(post) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const authorDetails = authors.find(person => person.name === post.author);
      if (authorDetails) {
        post.author = authorDetails;
        console.log("ok, post hydrated with author info");
        resolve(post);
      } else {
        reject(Error("Author not Found!"));
      }
    }, 200);
  });
}

function dehydratePostTitle(post) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      delete post.title;
      console.log("ok, applied transformation to remove title");
      resolve(post);
    }, 200);
  });
}

// ok, here is how it looks regarding this question..
let source$ = fromPromise(getPostById(1)).pipe(
  flatMap(post => {
    return hydrateAuthor(post);
  }),
  flatMap(post => {
    return dehydratePostTitle(post);
  }),
  catchError(error => of(`Caught error: ${error}`))
);

source$.subscribe(console.log);
输出数据:

ok, post found!
ok, post hydrated with author info
ok, applied transformation to remove title
{ author:
   { name: 'Wes Bos',
     twitter: '@wesbos',
     bio: 'Canadian Developer' },
  id: 1 }
关键部分,相当于以下使用普通承诺控制流:

getPostById(1)
  .then(post => {
    return hydrateAuthor(post);
  })
  .then(post => {
    return dehydratePostTitle(post);
  })
  .then(author => {
    console.log(author);
  })
  .catch(err => {
    console.error(err);
  });
我就是这样做的

之前

  public fetchContacts(onCompleteFn: (response: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => void) {
    const request = gapi.client.people.people.connections.list({
      resourceName: 'people/me',
      pageSize: 100,
      personFields: 'phoneNumbers,organizations,emailAddresses,names'
    }).then(response => {
      onCompleteFn(response as gapi.client.Response<gapi.client.people.ListConnectionsResponse>);
    });
  }

// caller:

  this.gapi.fetchContacts((rsp: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => {
      // handle rsp;
  });
public-fetchContacts(onCompleteFn:(响应:gapi.client.response)=>void){
const request=gapi.client.people.people.connections.list({
resourceName:'人/我',
页面大小:100,
personFields:'电话号码、组织、电子邮件地址、姓名'
})。然后(响应=>{
onCompleteFn(响应为gapi.client.response);
});
}
//来电者:
this.gapi.fetchContacts((rsp:gapi.client.Response)=>{
//处理可吸入悬浮粒子;
});
之后(ly?

public fetchContacts():可观察{
归来(
新承诺((解决、拒绝)=>{
gapi.client.people.people.connections.list({
resourceName:'人/我',
页面大小:100,
personFields:'电话号码、组织、电子邮件地址、姓名'
})。然后(结果=>{
决心(结果);
});
})
).pipe(映射((结果:gapi.client.Response)=>{
return result;//如果不更改响应中的任何内容,则实际上不需要映射。只需返回from(),调用方就会订阅它。
}));
}
//来电者
this.gapi.fetchContacts().subscribe((rsp:gapi.client.Response)=>{
//处理rsp
}),(错误)=>{
//处理错误
});

相当于promise.then()的RxJS序列?

public fetchContacts(): Observable<gapi.client.Response<gapi.client.people.ListConnectionsResponse>> {
    return from(
      new Promise((resolve, reject) => {
        gapi.client.people.people.connections.list({
          resourceName: 'people/me',
          pageSize: 100,
          personFields: 'phoneNumbers,organizations,emailAddresses,names'
        }).then(result => {
          resolve(result);
        });
      })
    ).pipe(map((result: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => {
      return result; //map is not really required if you not changing anything in the response. you can just return the from() and caller would subscribe to it.
    }));
  }

// caller

this.gapi.fetchContacts().subscribe(((rsp: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => {
  // handle rsp
}), (error) => {
  // handle error
});
比如说

function getdata1 (argument) {
        return this.http.get(url)
            .map((res: Response) => res.json());
    }

    function getdata2 (argument) {
        return this.http.get(url)
            .map((res: Response) => res.json());
    }

    getdata1.subscribe((data1: any) => {
        console.log("got data one. get data 2 now");
        getdata2.subscribe((data2: any) => {
            console.log("got data one and two here");
        });
    });

我总是看到可观察序列以subscribe()结尾。因为这只是可观察物体的函数,有什么理由这样做吗?是启动序列的功能吗?确实如此。如果没有通过subscribe传递的观察者,则您的观察者将不会发出任何数据,因此您不会看到任何数据流。我建议您查看以下内容:。官方文件
承诺可能更令人满意。然后
.flatMap
而不是
.map
。仅供参考,这与
承诺
第三次
版本错误不完全相同,然后
将被
捕获。副作用:在将回调转换为可观察后,更改检测也开始工作。我对RxJS非常陌生,但考虑到我们在这里只处理一个事件的初始流,
mergeMap()
因此实际上没有任何要合并的内容,我相信在这种情况下,我们可以使用
concatMap()
switchMap()
实现完全相同的效果。我得到了正确的答案吗…?完美的答案,但现在flatMap已经去润滑了!新方法是什么?flatMap->mergeMap
public fetchContacts(): Observable<gapi.client.Response<gapi.client.people.ListConnectionsResponse>> {
    return from(
      new Promise((resolve, reject) => {
        gapi.client.people.people.connections.list({
          resourceName: 'people/me',
          pageSize: 100,
          personFields: 'phoneNumbers,organizations,emailAddresses,names'
        }).then(result => {
          resolve(result);
        });
      })
    ).pipe(map((result: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => {
      return result; //map is not really required if you not changing anything in the response. you can just return the from() and caller would subscribe to it.
    }));
  }

// caller

this.gapi.fetchContacts().subscribe(((rsp: gapi.client.Response<gapi.client.people.ListConnectionsResponse>) => {
  // handle rsp
}), (error) => {
  // handle error
});
function getdata1 (argument) {
        return this.http.get(url)
            .map((res: Response) => res.json());
    }

    function getdata2 (argument) {
        return this.http.get(url)
            .map((res: Response) => res.json());
    }

    getdata1.subscribe((data1: any) => {
        console.log("got data one. get data 2 now");
        getdata2.subscribe((data2: any) => {
            console.log("got data one and two here");
        });
    });