角度/离子链接HTTP呼叫不同步

时间:2017-12-18 14:21:28

标签: angular ionic-framework promise api-eveonline

我目前正在使用一个有点痛苦的API:D API不会返回我的应用程序所需的完整信息,这意味着我必须进行多次调用才能获得所需的完整信息。此外,我正在努力保持头脑,所以如果没有很好地解释,请告诉我!

问题的主要细节

当前的API流程看起来有点像这样:

  1. 获取“群组ID”列表(请参阅回复1)。

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

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

  4. 构建一个包含所有细节的大树。

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

  6. 当尝试在正确的位置返回正确的值时会出现问题,因为我在异步承诺中的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"
        ]
      }
    }
    

2 个答案:

答案 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运算符改变数据的情况下轻松调试。

有关rxjs officiel documentation website的更多详情。

答案 1 :(得分:0)

我一直在寻找某种方式来完成异步调用序列,然后转到该男孩的文章。简而言之:使用Observables的类forkJoin方法。

Look for the section named forkJoin