尽管有捕获,被拒绝的 Promise 仍会中断循环

问题描述

我正在创建一个循环来使用具有内置承诺的函数来创建/更新用户

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,createduser,data.users[0].id);//Create update function
      promises.push(update); //Store function in array
      i++;
    } else {
      create = createNewUser(url,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,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`,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 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 Status: ${err}`)
            } else {
              reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Status: ${err}`)
            }
            });
    });
};

const getUsers = (url,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);
    });
});
};

当每个 promise 都完成时,代码和循环运行良好,但是一旦 promise 被拒绝,循环就会中断。我收到错误消息,例如:

XXX 上的错误错误:请求失败,状态代码为 422 错误文本: 使用此用户名用户已存在 节点:内部/进程/承诺:246 triggeruncaughtException(err,true /* fromPromise */); ^

[UnhandledPromiseRejection:这个错误是由抛出 在没有 catch 块的异步函数内部,或者通过拒绝一个 未使用 .catch() 处理的 promise。被拒绝的承诺 原因“错误代码:422:XXX,错误文本:具有此用户名用户 已经存在,错误状态:错误:请求失败,状态码 422"。] { }

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

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

解决方法

 public  function actionView()
{


    $this->view->title = 'List Hotels';
    $items = ArrayHelper::map(Hotel::find()->all(),'id','name');

        return $this->render('index',[
            'items' => $items,]);

}

这是不准确的。您没有在该数组中存储函数,您实际上在这里调用了 <?php /* @var $this yii\web\View */ use yii\helpers\Html; $this->title = 'Hotel list'; $this->params['breadcrumbs'][] = $this->title; ?> <?php foreach ($items as $item): ?> <p> <?= $item-> name ?></p> <p> <?= $item->address ?></p> <p> <?= $item->description ?></p> <?php endforeach; ?> /update = updateUser(url,okapikey,createduser,data.users[0].id);//Create update function promises.push(update); //Store function in array create = createNewUser(url,createduser);//Create create function promises.push(create); //Store function in array 函数并将结果 promise 存储在数组中。然后,在实际调用 updateUser 数组上的 createNewUser 之前,您的循环继续(由于 await)执行更多 getUser 操作。与此同时,一些承诺可能已经被拒绝,而没有附加任何处理程序。

这与Waiting for more than one concurrent await operationAny difference between await Promise.all() and multiple await?中讨论的问题基本相同。

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

Promise.allSettled

(我试过avoid awaiting any .then(…) chains