我目前正在使用一个有点痛苦的API:D API不会返回我的应用程序所需的完整信息,这意味着我必须进行多次调用才能获得所需的完整信息。此外,我正在努力保持头脑,所以如果没有很好地解释,请告诉我!
问题的主要细节
当前的API流程看起来有点像这样:
获取“群组ID”列表(请参阅回复1)。
使用该列表,为每个组ID获取组中的组详细信息和类型(请参阅响应2)。
使用组详细信息,为每种类型获取类型名称(请参阅响应3)。
构建一个包含所有细节的大树。
使用单独的终点,获取所有“技能”并相应地更新树(请参阅响应4)。
当尝试在正确的位置返回正确的值时会出现问题,因为我在异步承诺中的promises中嵌套了promises:O
主要的API端点和示例可以在https://esi.tech.ccp.is/latest/找到。
我当前的代码看起来有点像下面(我试图按照调用的顺序列出函数)。
问题是,我需要找到以下几点:
已返回组列表。
对于每个组,已返回包含的类型。
skillTree对象添加了一个新属性,格式如下。
技能树目标:
skillTree = {
"groupName": [
"skillID": {
"level": 0;
},
"skill2ID": {
"level": 0;
},...
],
"group2Name": [
"skillID" {
"level": 0;
},...
],...
};
tab-skills-all.ts(调用main函数):
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 Provider - 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() - 返回组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 Provider - 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 :(得分:0)
你应该使用Observables,因为Observable很冷,所以你可以创建它们,将它们存储在一个数组中,然后组合结果,这样你的http请求就会同时被触发,收集你需要的所有内容的详细信息。
这里是伪代码(因为我不会复制你所拥有的整个实现),一个Observable链解决你的问题:
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数组来添加详细信息对技能。然后你可以订阅它并获得技能。
我强烈建议使用Observables而不是像这样的大案例的promises,因为Observable允许你做更多的事情,并且在不使用do
运算符改变数据的情况下轻松调试。
答案 1 :(得分:0)
我一直在寻找某种方式来完成异步调用序列,然后转到该男孩的文章。简而言之:使用Observables的类forkJoin方法。