2016-04-04 13 views
2

私は作業しているNodeJSスクリプトを持っていますが、私が持っている最大の問題は、これらすべての約束を見ることは醜いだけでなく、時間が経つにつれて維持するのが難しいことですに。NodeJS PromiseをPromise.allに変換する

Promise.all()メソッドを使用して、これらの個別の約束事を1つに変換したいのですが、同じ機能をどのように取得し、この方法を使用して1つの約束事から別の約束事に変数を割り当てることができないのか分かりません。

たとえば、私の2番目の約束:methods.login()は、ほぼすべての約束事で使用されるsessionIdを返します。どのように私はその変数を割り当てて、Promise.all()を使ってさらに依存する約束に渡すのですか?ここで

は私の現在のコードです:彼らは、並列に実行し、それらのすべてが終了するまで待機する必要がある場合

var zabbixApi = require('./zabbixapi.js'); 
var methods = require('./methods.js'); 
var fs  = require('fs'); 
var SESSIONID; 

function main() { 
    var apiVersion, loggedOut, numTemplates, numHosts, numHostGroups, numItems; 
    var templates = [] 
     , hostGroups = [] 
     , hosts = []; 

    /*var promises = []; 
    promises.push(zabbixApi(methods.getApiVersion())); 
    promises.push(zabbixApi(methods.login(SESSIONID))); 
    promises.push(zabbixApi(methods.getHostGroups(SESSIONID))); 
    promises.push(zabbixApi(methods.getTemplates(SESSIONID))); 
    promises.push(zabbixApi(methods.getHosts(SESSIONID))); 
    // promises.push(zabbixApi(methods.configExport(hostIds, templateIds, groupIds, SESSIONID))); 
    promises.push(zabbixApi(methods.logout(SESSIONID))); 

    Promise.all(promises).then(function (values) { 
     console.log('All promises completed.'); 

    }, function (reason) { 
     console.log('Error completing promises: ' + reason); 
    });*/ 


    // Get API version 
    zabbixApi(methods.getApiVersion()) 

    // If successful, login to the API 
    .then(function (version) { 
     apiVersion = version.result; 

     // Verify that the API version returned is correct 
     if (apiVersion.length < 5 || !apiVersion) { 
      console.log('Error occurred retrieving API version: ' + version.error.data); 
      return 1; 
     } else { 
      return zabbixApi(methods.login(SESSIONID)); 
     } 

    }, function (error) { 
     console.log('Error occurred retrieving API version: ' + error); 
     return 1; 

     // If login successful, continue operations until logged out or error 
    }).then(function (auth) { 
     SESSIONID = auth.result; 

     if (!SESSIONID) { 
      console.log('Error retrieving session id: ' + auth.error.data); 
      return 1; 
     } else { 
      console.log('Logged in successfully!'); 
      return zabbixApi(methods.getHostGroups(SESSIONID)); 
     } 

    }, function (error) { 
     console.log('Error occurred authenticating: ' + error); 
     return 1; 

     // Attempt to retrieve all hostgroup information 
    }).then(function (hostgroups) { 
     numHostGroups = hostgroups.result.length; 
     hostGroups = hostgroups.result; 

     if (!numHostGroups) { 
      console.log('Error occurred retrieving host groups: ' + hostgroups.error.data); 
      return 1; 
     } else { 
      return zabbixApi(methods.getTemplates(SESSIONID)); 
     } 


    }, function (error) { 
     console.log('Error occurred retrieving host groups: ' + error); 
     return 1; 

     // Attempt to retrieve host information 
    }).then(function (template) { 
     numTemplates = template.result.length; 
     templates = template.result; 

     if (!numTemplates) { 
      console.log('Error occurred retrieving templates: ' + template.error.data); 
      return 1; 
     } else { 
      return zabbixApi(methods.getHosts(SESSIONID)); 
     } 


    }, function (error) { 
     console.log('Error occurred retrieving templates: ' + error); 
     return 1; 

     // Attempt to retrieve host information 
    }).then(function (hosts) { 
     numHosts = hosts.result.length; 
     hosts = hosts.result; 

     if (!numHosts) { 
      console.log('Error occurred retrieving host groups: ' + hosts.error.data); 
      return 1; 
     } else { 
      var groupIds  = [] 
       , hostIds  = [] 
       , templateIds = []; 

      // Extract all groupIds for host groups 
      for (var i = 0; i < numHostGroups; i++) { 
       groupIds[i] = hostGroups[i].groupid; 
      } 
      // Extract all hostIds for hosts 
      for (var i = 0; i < numHosts; i++) { 
       hostIds[i] = hosts[i].hostid; 
      } 
      // Extract all templateIds for templates 
      for (var i = 0; i < numTemplates; i++) { 
       templateIds[i] = templates[i].templateid; 
      } 
      return zabbixApi(methods.configExport(hostIds, templateIds, groupIds, SESSIONID)); 
     } 

    }, function (error) { 
     console.log('Error occurred retrieving host groups: ' + error); 
     return 1; 

     // Attempt to retrieve configuration information 
    }).then(function (config) { 
     //console.log(config); 
     if (config.error) { 
      console.log('Error occurred retrieving configuration: ' + config.error.message + ': ' + config.error.data); 
      return 1; 
     } else { 
      if (!writeToFile(config)) { 
       return 1; 
      } else { 
       console.log('Configuration details exported successfully.'); 

      } 
      return zabbixApi(methods.logout(SESSIONID)); 
     } 

    }, function (error) { 
     console.log('Error occurred retrieving configuration: ' + error); 
     return 1; 

     // Attempt to logout of API, if logout successful exit safely 
    }).then(function (logout) { 
     loggedOut = logout.result; 
     if (!loggedOut) { 
      console.log('Error logging out: ' + logout.error.data); 
      return 1; 
     } else { 
      console.log('Logged out successfully!'); 
      return 0; 
     } 

    }, function (error) { 
     console.log('Error occurred logging out: ' + error); 
     return 1; 
    }); 
} 

function writeToFile (config) { 
    fs.writeFile('zabbix_config_export.json', JSON.stringify(config), function (err) { 
     if (err) { 
      return console.log('Error writing configuration to file: ' + err); 
     } 
    }); 
    return true; 
} 
main(); 
+2

多くのものが必要なものをチェーンし、残りの部分を 'Promise.all'とします。 – dandavis

+0

@dandavis Promise.all()呼び出しで個々の約束から返されたデータをどのように使用できますか? –

+0

かもしれない... Array#reduce + Promise#catch? – user943702

答えて

2

並行して実行できる操作ではPromise.all()を使用できますが、特定の順序で実行する必要がある操作には使用できません。

コードを見ると、いくつかの操作を並行して実行できる場所がいくつかありますが、すべての操作をそのように行うことはできません。あなたが、この一般的な順序で物事を行うことができます表示されます。

var zabbixApi = require('./zabbixapi.js'); 
var methods = require('./methods.js'); 
var fs  = require('fs'); 
var SESSIONID; 

function logout() { 
    if (SESSIONID) { 
     var p = zabbixApi(methods.logout(SESSIONID)); 
     // clear SESSIONID to show that we've already launched a logout attempt, no need to try again 
     SESSIONID = null; 
     return p; 
    } else { 
     return Promise.resolve(); 
    } 
} 

function main() { 
    var apiVersion, hostGroups, templates, hosts; 

    // Get API version 
    zabbixApi(methods.getApiVersion()) 

    // If successful, login to the API 
    .then(function (version) { 
     apiVersion = version.result; 

     // Verify that the API version returned is correct 
     if (!apiVersion || apiVersion.length < 5) { 
      throw new Error('Error occurred retrieving API version: ' + version.error.data); 
     } else { 
      return zabbixApi(methods.login(SESSIONID)); 
     } 

    }, function (error) { 
     throw new Error('Error occurred retrieving API version: ' + error); 

    // If login successful, continue operations until logged out or error 
    }).then(function (auth) { 
     SESSIONID = auth.result; 

     if (!SESSIONID) { 
      throw new Error('Error retrieving session id: ' + auth.error.data); 
     } else { 
      console.log('Logged in successfully!'); 

      // now that we are logged in, a number of operations can be launched in parallel 
      return Promise.all([ 
       zabbixApi(methods.getHostGroups(SESSIONID), 
       zabbixApi(methods.getTemplates(SESSIONID), 
       zabbixApi(methods.getHosts(SESSIONID) 
      ]); 
     } 
    }, function (error) { 
     throw new Error('Error occurred authenticating: ' + error); 

    // we have hostGroups, templates and hosts here 
    }).then(function(r) { 
     // r[0] = hostGroups, r[1] = templates, r[2] = hosts 

     // check hostGroups 
     hostGroups = r[0].result; 
     if (!hostGroups.length) { 
      throw new Error('Error occurred retrieving host groups: ' + hostgroups.error.data); 
     } 

     // check templates 
     templates = r[1].result; 
     if (!templates.length) { 
      throw new Error('Error occurred retrieving templates: ' + template.error.data); 
     } 

     // check host information 
     hosts = r[2].result; 
     if (!hosts.length) { 
      throw new Error('Error occurred retrieving host groups: ' + hosts.error.data); 
     } 

     // utility function for retrieving a specific property from each array of objects 
     function getIds(array, prop) { 
      return array.map(function(item) { 
       return item[prop]; 
      }); 
     } 

     var groupIds = getIds(hostGroups, "groupid"); 
     var hostIds = getIds(hosts, "hostid"); 
     var templateIds = getIds(templates, "templateid"); 
     return zabbixApi(methods.configExport(hostIds, templateIds, groupIds, SESSIONID)); 
    }).then(function(config) { 
     if (config.error) { 
      throw new Error('Error occurred retrieving configuration: ' + config.error.message + ': ' + config.error.data); 
     } 
     // simultaneously write to file and logout (since these are not dependent upon one another) 
     return Promise.all(logout(), writeToFile(config)); 
    }).then(function() { 
     // success here, everything done 
    }, function(err) { 
     // upon error, try to logout and rethrow earlier error 
     return logout().then(function() { 
      throw err; 
     }, function() { 
      throw err; 
     }); 
    }).then(null, function(err) { 
     // error here 
     console.log(err); 
    }); 

} 

function writeToFile (config) { 
    return new Promise(function(resolve, reject) { 
     fs.writeFile('zabbix_config_export.json', JSON.stringify(config), function (err) { 
      if (err) { 
       return Promise.reject(new Error('Error writing configuration to file: ' + err)); 
      } 
      resolve(); 
     }); 
    }); 
} 
main(); 

これはまた、他のいくつかの重要な構造的変更/修正ます:

  1. どれを次のように達成することができ

    getApiVersion 
    Login to session 
    In parallel (getHostGroups, getTemplates, getHosts) 
    configExport previous results 
    In parallel (logout, writeToFile) 
    

    あなたが拒否/キャッチハンドラを持っているときに、拒否された約束を返すか、そのハンドラからスローされなければ、約束チェーンはあなたが望むものではなく、あなたがほぼすべての拒否ハンドラあなたは持っていた。

  2. 単一の約束ごとに拒否ハンドラを持つ必要はありません。とにかくチェーンを止めることを拒否するつもりならば、拒絶の理由が説明的であることを確認し、すべての失敗をチェーンの最後に一箇所だけ記録することができます。
  3. これは、相互に依存しないために操作が並行して実行できる2つの場所でPromise.all()を使用しますが、コードロジックはそれらがすべて完了したときを知りたいと考えています。
  4. writeToFile()が約束を返すように変更されました。
  5. あなたが最初!apiVersionをチェックする必要がありますので、apiVersionをチェックするときに、2つの条件スワップ
  6. (ログインが成功した場合)、少なくともログアウトを試みる安全にいくつかのエラーパスで呼び出すことができますlogout()機能ので、すべてのエラーと成功のパスを作成します。
+0

偉大な実装!しかし、私はこのコードを実行しようとするとエラーが発生します:エラー:配列メソッドは、配列を渡す必要があります。どのように解決するかについての任意のアイデア?それがどこに投げられているのかわからない。 –

+0

修正:それは.then(null、function(err){console.log(err);}ステートメント –

+0

私はそれを修正しました。問題はPromise.all(...)の呼び出しにありました。それは配列であり、呼び出しとは別の引数ではありません。問題を修正するためにあなたの答えを編集しました。 –

1

Promises.allは、非同期機能を処理することを意図しています。共有するコードの約束は独立していないので、Promises.allはここでは使用できません。 Promises.allの使用方法については、this referenceをご覧ください。

関連する問題