title: Javascript: how to pass additional variables to a promise .catch function
body: <p>I have found out how to pass additional variables to the promise .then function by using Promise.all. But how can I pass these variables to the .catch function?</p>
  
  <p>My abstracted code:</p>
  
  <pre><code>// global variable url
  var url = [url1, url2, url3];
  
  for (i = 0, i &lt; url.length, i++) {
      // run a promise.all to pass some additional variables to the next .then
      Promise.all([xhr(url[i]), i]).then(function([response, i]) {
          // do something with the response and variable i
          alert(url[i] + " responded: " + response);
  
      }).catch(function(e) {
          // I need variable i also to be available here!
          alert(url[i] + " failed to respond");
  
      });
  }
  
  function xhr(url) {
      return new Promise(function(resolve, reject) {
          // xmlhttprequest with url
          // resolves with the response
          // or rejects with an error message
  
      });
  }
  </code></pre>
  
  <p>This is just a very abstract code to explain that I need variable i also to be available in the .catch function.</p>
  
  <p>How to achieve this?</p>
  
  <p>EDIT:</p>
  
  <p>In response to the answers and my comments to them, here is my complete code with using <code>let</code> in the for loop. I think now it is a very neat use of promises to search different search engines in parallel and use the first useful hit.
  I use <code>Promise.any</code> - an inverted <code>Promise.all</code> - to get the first resolved promise from an array of promises. And I use the for loop to prepare the promises for the Promise.any. nzbDonkeySettings is a global variable with my settings:</p>
  
  <pre><code>// modifiy the promise prototype to add function "any"
  // from https://stackoverflow.com/questions/39940152/get-first-fulfilled-promise
  Promise.prototype.invert = function() {
      return new Promise((res, rej) =&gt; this.then(rej, res));
  };
  Promise.any = function(ps)  {
      return Promise.all(ps.map((p) =&gt; p.invert())).invert();
  };
  
  // function to search and download the nzb file
  function searchNZB(nzbHeader) {
  
      // prepare the promises for all search engines
      var getNZB = []; // the promise array
      for (let i = 0; i &lt; nzbDonkeySettings.searchengines.length; i++) {
          if (nzbDonkeySettings.searchengines[i].active) { // but only for "active" search engines
              getNZB[i] = new Promise(function(resolve, reject) {
  
                  // first search for the nzb header
                  var nzbSearchURL = nzbDonkeySettings.searchengines[i].searchURL.replace(/%s/, encodeURI(nzbHeader));
                  var options = {
                      "url": nzbSearchURL,
                      "responseType": "text",
                      "timeout": 20000
                  };
                  xhr(options).then(function(response) {
                      // if we have a response, check if we have a result
                      var re = new RegExp(nzbDonkeySettings.searchengines[i].searchPattern, "i");
                      if (re.test(response)) {
                          // if we have a result, generate the url for the nzb file
                          var nzbDownloadURL = nzbDonkeySettings.searchengines[i].downloadURL.replace(/%s/, response.match(re)[nzbDonkeySettings.searchengines[i].searchGroup]);
                          // and download the nzb file
                          var options = {
                              "url": nzbDownloadURL,
                              "responseType": "text",
                              "timeout": 120000
                          };
                          xhr(options).then(function(response) {
                              // if we have a response, check if it is a nzb file
                              if (response.match(/&lt;nzb.*&gt;/i)) {
                                  // if it is a nzb file, resolve with the nzb file
                                  resolve(response);
                              } else {
                                  // if it is not a nzb file, reject
                                  reject(new Error(nzbDonkeySettings.searchengines[i].name + ": " + "the downloaded file is not a valid nzb file"));    
                              }
                          }).catch(function(e) {
                              // if the download failed, reject
                              reject(new Error(nzbDonkeySettings.searchengines[i].name + ": " + "an error occurred while trying to download the nzb file"));  
                          });
                      } else {
                          // if we have no result, reject
                          reject(new Error(nzbDonkeySettings.searchengines[i].name + ": " + "no nzb file found"));
                      }   
                  }).catch(function(e) {
                      // if we have no response, reject
                      reject(new Error(nzbDonkeySettings.searchengines[i].name + ": " + "an error occurred while searching for the nzb file"));   
                  });
  
              });
          }
      }
  
      // return a promise
      return new Promise(function(resolve, reject) {
  
          // lets "race" the promises and get the result from the first resolved promise
          Promise.any(getNZB).then(function(nzbFile) {
              // resolve with the nzbFile
              resolve(nzbFile);
          }).catch(function(e) {
              // if we have no results, reject
              reject(new Error("no search engine returned any usable result"));   
          });     
  
      });
  
  }
  </code></pre>