2017-12-18 330 views
0

我目前正在使用一个有点痛苦的API:D API不会返回我的应用程序所需的全部信息,这意味着我必须多次调用得到所需要的全部信息。另外,我努力保持我的头一轮就那么如果它不能很好地解释只是让我知道!角度/离子链接HTTP呼叫不同步

问题

目前API流的主要细节看起来有点像这样:

  1. 获取 '群组的ID' 的列表(见反应1)。

  2. 使用该列表,对于每个组ID,获取组中的组详细信息和类型(请参见响应2)。

  3. 使用组详细信息,为每种类型获取类型名称(请参见响应3)。

  4. 建立一个大的树的所有细节。

  5. 使用单独的终点,获取所有“技能”并相应地更新树(请参见响应4)。

这个问题是试图在正确的位置是所有不同步返回正确的值时,因为我嵌套承诺在异步承诺承诺:o

主要API端点和示例可以在https://esi.tech.ccp.is/latest/找到。

我目前的代码看起来有点像下面(我尝试按顺序列出函数)。

的问题是,我需要找到一点:

  • 组的名单已返回。

  • 对于每个组类型包括已退回。

  • skillTree对象已经添加了一个新的属性,这是在下面的格式。

技能树目的:

skillTree = { 
    "groupName": [ 
     "skillID": { 
      "level": 0; 
     }, 
     "skill2ID": { 
      "level": 0; 
     },... 
    ], 
    "group2Name": [ 
     "skillID" { 
      "level": 0; 
     },... 
    ],... 
}; 

制表技能all.ts(调用主要功能):

 eveESI.buildSkillTree().then(() => { 
      // Need to add names to all skills in tree... 
      console.log('Completed skill tree:'); 
      console.log(eveESI.skillTree); 
     }).catch((error) => { 
      // Do error handling... 
     }); 

eveESI提供商 - buildSkillTree():

 buildSkillTree(){ 
     return new Promise((resolve, reject) => { 
      this.getSkillGroups().then((groups) => { 
       console.log('Success: Fetched groups successfully!'); 
       console.log(groups); 

       // Process groups. First get group details including types. Then for each group push to main array. 
       for (var i in groups) { 
        if (groups.hasOwnProperty(i)) { 
         this.getSkillsInGroup(groups[i]).then((data) => { 

          var groupDetails = JSON.parse(data.toString()); 

          var types = groupDetails.types; 
          var name = groupDetails.name; 

          console.log('Success: Fetched types for group ' + name + ' successfully!'); 

          // Declare and build temp group object before we push it to main skill object... 
          var tempGroupObj = []; 

          // For each skill type in the group add to temporary array... 
          for (var n in types) { 
           if (types.hasOwnProperty(n)) { 
            tempGroupObj[types[n]] = {}; 
            tempGroupObj[types[n]]['level'] = 0; 
           } 
          } 

          console.log(tempGroupObj); 

          this.skillTree[name] = tempGroupObj; 

         }).then(() => { 

         }).catch((error) => { 
          // Do error handling... 
          console.log(error); 
         }); 
        } 
       } 

       resolve(); 
      }).catch((error) => { 
       // Do error handling... 
       reject(); 
      }); 
     }); 
    } 

eveESI Provider - getSkillGroups() - returns [...]组ID的响应见的1:

 getSkillGroups(){ 
     return new Promise((resolve, reject) => { 
      this.http.get(this.apiRoot + 'universe/categories/16/', { }, { Authorization: 'Basic YWUxYmIzZDU4ZmRiNDk1ZDk3ZTE1ZTE0OTIyZDc0ZDk6MnpsVjNLZzVHbTh4OHY5b2lUSENYOHVXR21PYjlHd2Rqc3htQ0NHOA=='}) 
      .then(reqResponse => { 
       // Returns {} of skill groups from category... 
       var responseJSON = JSON.parse(reqResponse.data); 

       resolve(responseJSON.groups); 
      }).catch(reqError => { 
       // Error. Return error message... 
       reject(); 
      }); 
     }); 
    } 

eveESI提供商 - getSkillsInGroup(ID) - 的组的信息返回{...}看到响应2:

getSkillsInGroup(id){ 
     return new Promise((resolve, reject) => { 
      this.http.get(this.apiRoot + 'universe/groups/' + id + '/', { }, { Authorization: 'Basic YWUxYmIzZDU4ZmRiNDk1ZDk3ZTE1ZTE0OTIyZDc0ZDk6MnpsVjNLZzVHbTh4OHY5b2lUSENYOHVXR21PYjlHd2Rqc3htQ0NHOA=='}) 
      .then(reqResponse => { 
       resolve(reqResponse.data); 
      }).catch(reqError => { 
       // Error. Return error message... 
       reject(); 
      }); 
     }); 
    } 

响应1(列出组ID的):

{ 
    "category_id": 16, 
    "name": "Skill", 
    "published": true, 
    "groups": [ 
    255, 
    256, 
    257, 
    258, 
    266, 
    268, 
    269, 
    270, 
    272, 
    273, 
    274, 
    275, 
    278, 
    505, 
    1209, 
    1210, 
    1213, 
    1216, 
    1217, 
    1218, 
    1220, 
    1240, 
    1241, 
    1545 
    ] 
} 

响应2(返回组细节和组类型):

{ 
    "group_id": 255, 
    "name": "Gunnery", 
    "published": true, 
    "category_id": 16, 
    "types": [ 
    3300, 
    3301, 
    3302, 
    3303, 
    3304, 
    3305, 
    3306, 
    3307, 
    3308, 
    3309, 
    3310, 
    3311, 
    3312, 
    3315, 
    3316, 
    3317, 
    11082, 
    11083, 
    11084, 
    12201, 
    12202, 
    12203, 
    12204, 
    12205, 
    12206, 
    12207, 
    12208, 
    12209, 
    12210, 
    12211, 
    12212, 
    12213, 
    12214, 
    12215, 
    20327, 
    21666, 
    21667, 
    22043, 
    24563, 
    32856, 
    41403, 
    41404, 
    41405, 
    41406, 
    41407, 
    41408, 
    41537 
    ] 
} 

响应3(返回由ID类型的详细信息):

{ 
    "type_id": 3300, 
    "name": "Gunnery", 
    "description": "Basic turret operation skill. 2% Bonus to weapon turrets' rate of fire per skill level.", 
    "published": true, 
    "group_id": 255, 
    "market_group_id": 364, 
    "radius": 1, 
    "volume": 0.01, 
    "packaged_volume": 0.01, 
    "icon_id": 33, 
    "capacity": 0, 
    "portion_size": 1, 
    "mass": 0, 
    "dogma_attributes": [...], 
    "dogma_effects": [...] 
} 

的package.json

{ 
    "name": "name", 
    "version": "0.0.1", 
    "author": "author", 
    "homepage": "http://ionicframework.com/", 
    "private": true, 
    "scripts": { 
    "clean": "ionic-app-scripts clean", 
    "build": "ionic-app-scripts build", 
    "lint": "ionic-app-scripts lint", 
    "ionic:build": "ionic-app-scripts build", 
    "ionic:serve": "ionic-app-scripts serve" 
    }, 
    "dependencies": { 
    "@angular/common": "5.0.3", 
    "@angular/compiler": "5.0.3", 
    "@angular/compiler-cli": "5.0.3", 
    "@angular/core": "5.0.3", 
    "@angular/forms": "5.0.3", 
    "@angular/http": "5.0.3", 
    "@angular/platform-browser": "5.0.3", 
    "@angular/platform-browser-dynamic": "5.0.3", 
    "@ionic-native/browser-tab": "^4.4.2", 
    "@ionic-native/core": "4.4.0", 
    "@ionic-native/deeplinks": "^4.4.2", 
    "@ionic-native/http": "^4.4.2", 
    "@ionic-native/secure-storage": "^4.4.2", 
    "@ionic-native/spinner-dialog": "^4.4.2", 
    "@ionic-native/splash-screen": "4.4.0", 
    "@ionic-native/sqlite": "^4.4.2", 
    "@ionic-native/sqlite-porter": "^4.5.0", 
    "@ionic-native/status-bar": "4.4.0", 
    "@ionic/storage": "^2.1.3", 
    "angular2-natural-sort": "0.0.2", 
    "angular2-swagger-client-generator": "0.0.22", 
    "cordova-android": "6.3.0", 
    "cordova-plugin-advanced-http": "^1.9.0", 
    "cordova-plugin-browsertab": "^0.2.0", 
    "cordova-plugin-compat": "^1.2.0", 
    "cordova-plugin-device": "^1.1.4", 
    "cordova-plugin-file": "^5.0.0", 
    "cordova-plugin-ionic-webview": "^1.1.16", 
    "cordova-plugin-native-spinner": "^1.1.3", 
    "cordova-plugin-secure-storage": "^2.6.8", 
    "cordova-plugin-splashscreen": "^4.0.3", 
    "cordova-plugin-statusbar": "^2.3.0", 
    "cordova-plugin-whitelist": "^1.3.1", 
    "cordova-sqlite-storage": "^2.1.2", 
    "ionic-angular": "3.9.2", 
    "ionic-plugin-deeplinks": "^1.0.15", 
    "ionic-plugin-keyboard": "^2.2.1", 
    "ionicons": "3.0.0", 
    "ngx-order-pipe": "^1.1.1", 
    "rxjs": "5.5.2", 
    "sw-toolbox": "3.6.0", 
    "swagger-angular-generator": "^1.2.1", 
    "uk.co.workingedge.cordova.plugin.sqliteporter": "^1.0.2", 
    "zone.js": "0.8.18" 
    }, 
    "devDependencies": { 
    "@ionic/app-scripts": "3.1.4", 
    "typescript": "2.4.2" 
    }, 
    "description": "An Ionic project", 
    "cordova": { 
    "plugins": { 
     "ionic-plugin-keyboard": {}, 
     "cordova-plugin-whitelist": {}, 
     "cordova-plugin-device": {}, 
     "cordova-plugin-splashscreen": {}, 
     "cordova-plugin-ionic-webview": {}, 
     "cordova-plugin-browsertab": {}, 
     "ionic-plugin-deeplinks": { 
     "URL_SCHEME": "_CUSTOMURLSCHEME", 
     "DEEPLINK_SCHEME": "https", 
     "DEEPLINK_HOST": "localhost", 
     "ANDROID_PATH_PREFIX": "/", 
     "ANDROID_2_PATH_PREFIX": "/", 
     "ANDROID_3_PATH_PREFIX": "/", 
     "ANDROID_4_PATH_PREFIX": "/", 
     "ANDROID_5_PATH_PREFIX": "/", 
     "DEEPLINK_2_SCHEME": " ", 
     "DEEPLINK_2_HOST": " ", 
     "DEEPLINK_3_SCHEME": " ", 
     "DEEPLINK_3_HOST": " ", 
     "DEEPLINK_4_SCHEME": " ", 
     "DEEPLINK_4_HOST": " ", 
     "DEEPLINK_5_SCHEME": " ", 
     "DEEPLINK_5_HOST": " " 
     }, 
     "cordova-plugin-secure-storage": {}, 
     "cordova-plugin-native-spinner": {}, 
     "cordova-plugin-advanced-http": {}, 
     "cordova-sqlite-storage": {}, 
     "cordova-plugin-statusbar": {}, 
     "uk.co.workingedge.cordova.plugin.sqliteporter": {} 
    }, 
    "platforms": [ 
     "android" 
    ] 
    } 
} 
+0

一些提示:添加与您可以从端点获得的响应相匹配的接口定义。根据以前的接口添加一个接口,该接口定义要获取的最终结果。将显式参数和返回类型添加到提供者/服务方法。我仍然不明白为什么PPL使用打字稿时没有最重要的功能... –

回答

0

你应该使用因为Observable是冷的,所以你可以创建它们,将它们存储在一个数组中,然后再合并它们结果,以便您的http请求同时被触发,收集您需要的所有内容的详细信息。

这里,在伪代码(我将不会复制你的整个实现),可观测链解决您的问题:

getSkillGroups() { 
    this.http.get(this.apiRoot + 'universe/categories/16/', {}, {Authorization: 'Basic YWUxYmIzZDU4ZmRiNDk1ZDk3ZTE1ZTE0OTIyZDc0ZDk6MnpsVjNLZzVHbTh4OHY5b2lUSENYOHVXR21PYjlHd2Rqc3htQ0NHOA=='}) 
     .switchMap(response1 => { 
      const groupsDetails: Observable<any>[] = []; 
      response1.groups.forEach(group => { 
       groupsDetails.push(this.getSkillsInGroup(group)); 
      }); 
      //This will return an array of requests ready to be fired right when you call subscribe on it 
      // When fired, the requests will be parallels, not sync. 
      return Observable.combineLatest(groupsDetails); 
     }); 
} 

getSkillsInGroup(id){ 
    return this.http.get(this.apiRoot + 'universe/groups/' + id + '/', { }, { Authorization: 'Basic YWUxYmIzZDU4ZmRiNDk1ZDk3ZTE1ZTE0OTIyZDc0ZDk6MnpsVjNLZzVHbTh4OHY5b2lUSENYOHVXR21PYjlHd2Rqc3htQ0NHOA=='}) 
     .map(response2 => response2.data); 
} 

一旦你调用getSkillGroups(),你得到的response2数组的数据,这意味着你可以添加一个新的map操作符,创建一个Observable数组来添加细节到技能。然后你可以订阅它,你会得到技能。

我强烈建议使用,而不是承诺的大案像这样的观测量,如可观察到让你做的方式更多的事情,并没有使用do运营商改变数据方便调试。

有关rxjs officiel documentation website的更多详细信息。

+0

我一直完全被.map部分迷失了吗?你能解释它做了什么,为什么它与那个不同? –

+0

主要部分是'map'不触发observable,而。(实际上,创建promise会触发promise)。基本上,映射操作符将输入值转换为另一个(我意识到我犯了一个错误,应该是switchMap)。所以,map是“使用前一个操作符返回的值,返回这个值”。 switchMap更像是“使用返回值,返回这个Observable的结果”。检查这个模式:http://reactivex.io/documentation/operators/map.html它大大有助于理解地图。 – Supamiu

+0

现在我完全失去了:D那么,你将如何使用.subscribe来获得这个工作? –