2017-12-18 322 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來獲得這個工作? –