Rejected Promise 尽管有捕获但仍会中断循环

Rejected Promise breaks loop despite catch

我正在为 create/update 使用内置承诺的函数的用户创建一个循环:

for (const user of usersjson.users) {
 let getuser = getUser(url, okapikey, user[fieldMap.externalSystemId], 
 'externalSystemId'); //Check if user exists on the server
 await getuser
  .then(async (data) => {
    if (data.users.length != 0) { //If user exists in the array
      update = updateUser(url, okapikey, createduser, data.users[0].id);//Create update function
      promises.push(update); //Store function in array
      i++;
    } else {
      create = createNewUser(url, okapikey, createduser);//Create create function 
      promises.push(create); //Store function in array
      i++;
    }
  }).catch((err) => {
    console.error(err);
  });
  if (promises.length == 50 || i == usersjson.users.length) {//Run functions in batches of 50
     await Promise.allSettled(promises)
     .then((responses)=> {
       for (const response of responses) { //For each promise response
         if (response.status == 'fulfilled') { //If fulfilled
           if (response.value.status == 204) {
             console.log(`${response.value.status}: User ${response.value.request.path.substring(7)} was updated.`);
           } else {
             if (response.value.status == 201 && response.value.headers.location) {
               console.log(`${response.value.status}: User ${response.value.headers['location']} was created.`);
             } else {
               console.log(response.value.headers.location);
             }
           }
         } else { //Handle rejections
           console.log(`There was an error with the user:${response.value}`);
         }
       }
     }).catch((err)=> {
       console.log(err);
     });
     promises=[]; //Empty Promise array 
   }
}

async function updateUser(url, token, user, userid)
{
    return new Promise((resolve, reject) => {
        //Create headers for put request
        const options = {
            method: "put",
            headers: {
            'x-okapi-token': token,
            'x-okapi-tenant':'tenant',
            'Content-type':"application/json"
            }
        };
        //Make API get call
        user.id=userid; //Adding the required field ID to the JSON
        axios.put(`${url}/users/${userid}`, JSON.stringify(user), options)
            .then(response => {
              if (response.status == 204) {
                resolve(response);
              } else {
                reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
              }
            }).catch((err) => {
            console.error(`Error Code: ${err.response.status}`);
            if (typeof err.response.data == 'string') {
                console.error(err.response.data);
                reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
            } else if (err.response.data.errors[0].message) {
                console.error(`Error Text: ${err.response.data.errors[0].message}`);
                reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
            } else {
              reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
            }
            console.log(err.response);
            });
    });
};

async function createNewUser (url, token, user) {
    return new Promise((resolve, reject) => {
        //Create headers for put request
        const options = {
            headers: {
            'X-Okapi-token': token,
            'Content-type':"application/json"
            }
        };
        //Make API get call
        axios.post(`${url}/users`, JSON.stringify(user), options)
            .then(response => {
            if (response.status == 201) {
              resolve(response);
            } else {
              reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
            }
            }).catch((err) => {
            console.error(`Error on ${user.externalSystemId}: ${err}`);
            if (err.response.data && typeof err.response.data == 'string') {
                console.error(err.response.data);
                reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
            } else if (err.response.data.errors[0].message) {
                console.error(`Error Text: ${err.response.data.errors[0].message}`);
                reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
            } else {
              reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
            }
            });
    });
};

const getUsers = (url,user,password) =>
{
return new Promise((resolve, reject) => {
  //Create headers for POST request
  const options = {
    method: 'post',
    headers: {
       'Authorization': 'Basic '+Buffer.from(`${user}:${password}`).toString('base64')
    }
  }
  //Make API get call
  axios.get(url, options)
    .then(response => {
      resolve(response.data);
    }).catch((err) => {
      console.error(err);
      reject(err);
    });
});
};

当每个承诺都得到履行时,代码和循环工作正常,但一旦承诺被拒绝,循环就会中断。我收到错误消息,例如:

Error on XXX: Error: Request failed with status code 422 Error Text: User with this username already exists node:internal/process/promises:246 triggerUncaughtException(err, true /* fromPromise */); ^

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Error Code: 422: XXX, Error Text: User with this username already exists, Error Status: Error: Request failed with status code 422".] { }

查看代码和错误,我相信这是来自“createNewUser”函​​数。 我不确定为什么代码会中断 - 我向所有函数添加了 catch,处理了拒绝,并在代码主体中添加了 catch 语句,但循环仍然中断。

我需要的是即使一个函数失败,循环也能像往常一样继续(稍后我会将日志从 console.log 更改为实际日志文件)。

update = updateUser(url, okapikey, createduser, data.users[0].id);//Create update function
promises.push(update); //Store function in array

create = createNewUser(url, okapikey, createduser);//Create create function 
promises.push(create); //Store function in array

这是不准确的。您没有在该数组中存储 functions,您实际上在此处调用 updateUser/createNewUser 函数并将生成的承诺存储在数组中。然后,在实际调用 promises 数组上的 Promise.allSettled 之前,您的循环继续按顺序(由于 await)执行更多 getUser 操作。与此同时,一些承诺可能已经在没有附加任何处理程序的情况下被拒绝。

这与 and 中讨论的问题基本相同。

要修复它,请收集您稍后可以在数组中执行的实际函数:

let functions = [];
for (const user of usersjson.users) {
  i++;
  try {
    const data = await getUser(url, okapikey, user[fieldMap.externalSystemId], 'externalSystemId');
    if (data.users.length != 0) {
      functions.push(() =>
//                   ^^^^^
        updateUser(url, okapikey, createduser, data.users[0].id)
      ); // Create update function and store it in array
    } else {
      functions.push(() =>
//                   ^^^^^
        createNewUser(url, okapikey, createduser)
      ); // Create create function and store it in array
    }
  } catch(err) {
    console.error(err);
  }
  if (functions.length == 50 || i == usersjson.users.length) { // in batches of 50
    const promises = functions.map(fn => fn()); // Run functions
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    const responses = await Promise.allSettled(promises);
    for (const response of responses) {
      if (response.status == 'fulfilled') {
        if (response.value.status == 204) {
          console.log(`${response.value.status}: User ${response.value.request.path.substring(7)} was updated.`);
        } else {
          if (response.value.status == 201 && response.value.headers.location) {
            console.log(`${response.value.status}: User ${response.value.headers['location']} was created.`);
          } else {
            console.log(response.value.headers.location);
          }
        }
      } else {
        console.log(`There was an error with the user:${response.value}`);
      }
    }
    functions = []; // empty functions array 
  }
}

(我试过了