2017-11-30 12 views
1

시나리오 : mutiple 나머지 호출의 데이터를 하나의 단일 개체로 집계하고 노드를 통해 제공되는 초기 요청의 나머지 응답으로 반환해야합니다. js.Node.js에서 RxJs 관측 가능 결과를 반환하는 방법

문제점 : 관찰 응답이 완료 될 때까지 나머지 응답은 대기하지 않으므로 나머지 응답이 전달 된 후 돌연변이 (집계)가 실현됩니다.

//teamsController class invoked via GET /teams 

import * as Rx from 'rxjs/Rx' 
import http from 'axios' 
import Teams from '../models/teams' 

const teamsAPI = "http://localhost:8081/api/v1/teams/players/"; 
const usersAPI = "http://localhost:8082/api/v1/users/"; 

exports.getTeamByPlayer = function (req, res) { 

let username= req.get("username"); 

    Rx.Observable.fromPromise(fetchTeam(username)) 
     .map(team => { 
      Rx.Observable.from(team.players).subscribe(player => { 
       console.log(`Player name is ${player.username}`); 
       Rx.Observable.fromPromise(fetchUser(player.username)) 
        .map(avatar => avatar.avatar) 
        .subscribe(avatar => { 
         player.avatar = avatar; 
         console.log(player) 
        }) 
      }); 
      return team; 
     }) 
     .subscribe(result => { 
      console.log(`result is ${JSON.stingify(result)}`); 
      res.json(result); 

     }) 
} 


/** 
* Fetch a team by a player 
* 
* @param name The name of the team 
* @returns {Promise.<Teams>} 
*/ 
function fetchTeam(name) { 
    return http.get(teamsAPI + name) 
     .then(response => new Teams(response.data.data)) 
     .catch(error => { 
      throw new Error("todo: fill error message"); 
     }) 
} 

/** 
* Fetch a user given its username 
* 
* @param username The username of the player 
* @returns {Promise.<TResult>} 
*/ 
function fetchUser(username) { 
    return new Promise(function (resolve, reject) { 
     console.log(`fetching user: ${username}`); 
     resolve(); 
    }).then(() => { 
     return { 
      "avatar": { 
       "flagColor": "dummyValue", 
       "flagCrest": "dummyValue" 
      } 
     } 
    }); 

로그 결과

Player name is username1 
fetching user: username1 
Player name is username2 
fetching user: username2 
result is {"id":"5a1c2a4030c39e5d88aed087","name":null,"avatar":{"flagColor":"abcdefg","flagCrest":"hijklmn"},"description":"string","motto":"string","players":[{"userId":"59b94a7b8b68ef0a048e85c1","username":"username1","status":"ACTIVE","role":"ADMIN","dateJoined":1511795264314,"dateInvited":null,"score":0},{"userId":"59b94a7b8b68ef0a048e85c1","username":"username2","status":"ACTIVE","role":"MEMBER","dateJoined":1511795264314,"dateInvited":null,"score":0}],"score":0,"type":"TEAM","open":true,"location":{"longitude":0,"latitude":0,"country":"string"},"owner":"username1","dateCreated":1511795264314} 
{ userId: '59b94a7b8b68ef0a048e85c1', 
    username: 'username1', 
    status: 'ACTIVE', 
    role: 'ADMIN', 
    dateJoined: 1511795264314, 
    dateInvited: null, 
    score: 0, 
    avatar: { flagColor: 'dummyValue', flagCrest: 'dummyValue' } } 
{ userId: '59b94a7b8b68ef0a048e85c1', 
    username: 'username2', 
    status: 'ACTIVE', 
    role: 'MEMBER', 
    dateJoined: 1511795264314, 
    dateInvited: null, 
    score: 0, 
    avatar: { flagColor: 'dummyValue', flagCrest: 'dummyValue' } } 
AppServer를

: Node.js를 v8.7.0의 미들웨어 : RxJs 5.0.0-beta.12, Axios의 0.17.1 : 4.16.2, libs와 expess

답변

3

먼저 http 요청을 약속으로 변환하지 않습니다. 그것은 상황이 그들이 필요로하는 것보다 더 복잡하게 만듭니다. 일부 외부 소비자가 약속 기반의 API를 필요로하는 경우

function fetchTeam(name) { 
    return http.get(teamsAPI + name).map(res => new Teams(res.json().data)); 
} 

function fetchUser(username) { 
    return Rx.Observable.of({ 
     "avatar": { 
      "flagColor": "dummyValue", 
      "flagCrest": "dummyValue" 
     } 
    }); 
} 

, 다음 약속이 개인의 기능을 래핑 공공 기능을합니다.

초, 맵은 동기 연산자이므로 비동기 연산을 실행할 수 없으므로 구독 작업을 수행하는 비동기 연산자를 사용해야합니다. 관찰 할 수있는 스트림에서 자신이 구독하는 것을 발견하면 잘못된 일을합니다.

let username= req.get("username"); 

fetchTeam(username) 
    .switchMap(team => { // switchMap will subscribe to inner observables 
     //build observables for fetching each avatar, pay close attention, I'm mixing the array map operator and the rx map operator in here 
     let players$ = team.players.map(player => fetchUser(player.username).map(avatar => avatar.avatar)); 

     return Rx.Observable.forkJoin(players$); // use forkjoin to executre requests 
    }, (team, playerAvatars) => { // use second switchMap argument to combine results 
     team.players.forEach((player, idx) => player.avatar = playerAvatars[idx]); 
     return team; 
    }) 
    .subscribe(result => { 
     console.log(`result is ${JSON.stingify(result)}`); 
     res.json(result); 

    }); 
+0

고맙습니다! 팀 객체의 중첩 된 객체 중 일부를 업데이트하는 데 사용되는 모범 사례는 무엇입니까? – cparaskeva

+0

당신이 무엇을 요구하고 있는지 잘 모르겠습니다. – bryan60

+0

이 코드 라인은 플레이어가 $ = team.players.map (player => fetchUser (player.username) .map (avatar => avatar.avatar)) 완벽한 일치 상태의 사용자를 가져 오도록합니다. team.players 위치로. 그러나 팀이 100 명이라면 100 번 전화를하는 것이 불충분 할 것입니다. 따라서 새로운 웹 서비스는 모든 사용자 이름을 취하고 무작위 순서로 아바타 목록을 반환합니다. 그런 경우 키 (예 : 사용자 이름)를 기반으로 중첩 된 개체를 일치시키고 업데이트를 만드는 가장 좋은 방법은 무엇입니까? – cparaskeva