1

I have 2 arrays with email address that I want to feed to the function below, one after the other (not in parallel) and then perform a final function.

I've been looking at examples trying to figure out the correct way to chain these, but I think I'm now more confused than when I started. Tried playing with Promise.all to ensure steps completed before going to next but that was a disaster.

eg: (do array 1).then(do array 2).then(final function)

EmailArray.forEach(fGetUserId(X)) and push to IdArray

function fGetUserId(X) {

        $.ajax({ // get the Ids of users, return to populate IdArray
            url: xhost + "/portal/_api/web/SiteUsers?$select=Id&$filter=Email eq '" + X + "'",
            type: "GET", headers: { "Accept": "application/json;odata=verbose", }, //verbose
            success: function (data) {
                var xuserid = data.d.results[0].Id;
                return xuserid;
            },
            error: function (error) { alert(JSON.stringify(error)); }
        });    
    }

Help?

  • Can I not use $.when.apply something something? – BDC604 May 23 at 17:54
  • I'm not familiar with the syntax of JQuery, but I believe you can't use async await, .then(), .catch(), nor Promise.all(), because those are specific to native promises, not JQuery's promise-like syntax. – Cardin May 26 at 3:49
2

JQuery AJAX does not use native JS promises. You can observe this by the way they defined a success and error callback.

You can explore using fetch https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API, which is a reasonable browser API since you are already using Promise. I'll provide examples for both fetch and ajax:

/**
  @returns {Promise.<number|void>}
*/
async function fGetUserId(x) {
  /** @type {Promise.<any>} */
  let fetchPromise = fetch(xhost + "/portal/_api/web/SiteUsers?$select=Id&$filter=Email eq '" + X + "'", {
      method: "GET",
      headers: {
        Accept: "application/json;odata=verbose"
      }
    }
  ).then(x => x.json()); // convert response to JSON, aka Promise.<Response> to Promise.<any>

  let idPromise = fetchPromise
    .then(data => {
      var xuserid = data.d.results[0].Id;
      return xuserid;
    }) // Promise.<any> to Promise.<number>
    .catch(err => alert(JSON.stringify(err))); // in case of error, it becomes Promise.<void> instead, since we do not return anything within the catch()
  let userid = await idPromise; // Promise.<number|void> to number|void.
  return userid; // number (but actually Promise.<number|void> since fGetUserId has the async modifier in its signature)
}
/**
  @returns {Promise.<number|void>}
*/
async function fGetUserId(x) {
  /** @type {Promise.<number|void>} */
  let myPromise = new Promise((resolve, reject) => {
    $.ajax({
      url: xhost + "/portal/_api/web/SiteUsers?$select=Id&$filter=Email eq '" + X + "'",
      type: "GET",
      headers: { Accept: "application/json;odata=verbose", }, //verbose
      success: function (data) {
        var xuserid = data.d.results[0].Id;
        resolve(xuserid); // signify the promise succeeded with xuserid as return value
      },
      error: function (error) {
        alert(JSON.stringify(error));
        reject(); // signify the promise faulted with no return value
      }
    });
  });
  let userid = await myPromise; // Promise.<number|void> to number|void.
  return userid; // number (but actually Promise.<number|void> since fGetUserId has the async modifier in its signature)
}

There might be slight errors as I didn't test the code, but I hope the gist is still conveyed!

To call this code, you run this:

/** @type {string[]} */
let EmailArr = ["..", "..", ".."];

/** @type{(Promise.<number|void>)[]} */
let promiseArr = EmailArr.map(x => fGetUserId(x)); // map an array of emails to an array of promises

Promise.all(promiseArr) // wait for array of promises to resolve into array of userid, (aka Promise.<number|void>)[] to (number|void)[]
  .then(userids => console.log("done!", userids)
  .catch(err => console.error(err));

Note that Promise.all() itself is a Promise. You can use .then() to handle it as I did, or use await. Note that await can only be used in an async function, so you might want to declare a global anonymous async function:

(async () => {
  // You can use "await" here
})();
  • It grabs the xuserid fine, but I don't see how this is populating an array of Id's. Uncaught (in promise) TypeError: Cannot read property 'catch' of undefined. – BDC604 May 24 at 17:09
  • I've added some JSDoc/TypeScript annotations to help follow the flow. Btw did the error occur in fGetUserId? Which line is it? – Cardin May 26 at 4:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.