在Typescript中的地图内部分配Observable时获取未定义

时间:2017-05-20 06:13:02

标签: angular typescript rxjs observable

我试图理解可观察物并遇到一些挫折。

我有一个save()函数,可以调用initialize()来获取一些ID。在初始化内部,我在map方法(payload)中设置一个Observable,当我将结果记录到控制台时,它会被设置为正确的值。我试过切换地图订阅无济于事。

TLDR;从地图/订阅内部为预先提升的变量设置值的正确方法是什么?

相关:如果从对象序列化,那么observable的正确类型是什么?

save(post: Post, draftId?: number, postId?: number): Observable<any> {
    let payload: Observable<any>;
    if (!postId) {
        post.state = post.state ? post.state : 'unsaved';
        this.initialize(post)
            .subscribe((res) => {  //error here... cannot run 
                console.log('Waypoint: posts.service.ts:36');
                payload = res;
            });

    } else if (draftId && postId) {
        post.state = 'autosaved'
        return this.updateDraft(post, draftId);
    };
    return payload;
}

initialize(post: Post): Observable<any> {
    let resultPost: number;
    let resultDraft: number;
    var payload: Observable<any>;
    this.createPost(post)
        .subscribe(res => {
        resultPost = res.id;
        post.postId = res.id
        this.createDraft(post)
            .map(res => {
                resultDraft = res.id;
                let _payload = {
                    postId: resultPost,
                    draftId: resultDraft
                };
                console.log('Waypoint: posts.service.ts:62');
                payload = Observable.create(_payload); // looks good!
            }, (error) => { console.log(error) }).subscribe();

        });
    console.log(payload); //undefined :(
    return payload;
}

2 个答案:

答案 0 :(得分:1)

如果我理解正确,你的逻辑或多或少会像这样

  1. 首先通过createPost方法创建一个帖子,该方法返回一个 Observable
  2. subcribecreatePost并获得包含的结果 帖子ID
  3. 您使用帖子ID 来使用该方法创建草稿 createDraft再次返回Observable
  4. subscribecreateDraft,结果草稿 ID
  5. 然后最终您需要使用帖子ID 草稿ID 来填充 有效载荷变量,然后用于执行其他操作
  6. 我认为这是对的,你应该瞄准的是这样的事情

    let postId;
    let draftId;
    this.createPost(post)
        .map(res => {postId = res.id})
        .mergeMap(() => this.createDraft(post))  // mergeMap is same as flatMap
        .map(res => {draftId = res.id})
        .map(() => [postId, draftId])
        .subscribe(postDraftIds => payload = postDraftIds)
    

    还有其他方法可以使用Observable运算符来达到相同的目标(例如,您可以使用switchMap而不是mergeMap - 这是一个解释how switchMap works的非常好的链接),但我希望这很清楚

答案 1 :(得分:1)

回答你的一些问题:

  1. 的console.log(有效载荷);是未定义的,因为这行代码是在this.createDraft的订阅发生之前执行的

  2. 您使用的订阅方式太多,应该只有一个,实际上您想要接收数据的位置,在以前的情况下,您可以使用例如map/flatMap运算符。使用适当的运算符可以显着降低代码复杂性,如:

    save(post: Post, draftId?: number, postId?: number): Observable<Payload> {
        if (!postId) {
            post.state = post.state ? post.state : 'unsaved';
            return this.initialize(post);
        } else if (draftId && postId) {
            post.state = 'autosaved'
            return this.updateDraft(post, draftId);
        }
    
        return Observable.empty(); 
    }
    
    initialize(post: Post): Observable<Payload> {
        let resultPost: number;
        return this.createPost(post)
            .flatMap(res => {
                resultPost = res.id;
                post.postId = res.id;
                return this.createDraft(post)
            }.map(res =>  new Payload(resultPost, res.id));
    }}
    
  3. 导出类Payload {     postId:number;     draftId:number;

    constructor(postId: number, draftId: number) {
        this.postId = postId;
        this.draftId = draftId;
    }
    

    }

    事实上,initialize可以更多地重构为:

     initialize(post: Post): Observable<Payload> {
            return this.createPost(post)
                .flatMap(res => {
                    return Observable.zip(res.id, this.createDraft(post))
                }).map(res =>  new Payload(res[0], res[1].id));
        }
    
    1. 请勿使用any,而是使用特定类型
    2. 注意:我没有运行此代码,我只是建议您使用运算符

      //不知道为什么Payload没有正确呈现......