【问题标题】:How to execute promises simultaneously with forEach?如何与 forEach 同时执行承诺?
【发布时间】:2021-05-14 09:23:06
【问题描述】:

我有一个代码可以在我的系统中更新或创建新用户。它与 forEach 函数一起使用,效果很好。 但是,我想利用 Node.js 并同时执行多个更新/创建。 我试图创建一系列承诺,但我认为我构建的承诺是错误的。 这是可以正常工作的代码:

import usersjson from './jsons/users.json';
if (usersjson.users.length) {
    for (const user of usersjson.users) {
        let getuser = getUser(url, user.Id, 'Id');
            getuser.then((data) => {//Make a call to get user by id
                if (data.users.length != 0) { //If user exists
                    let update = updateUser(url, user, data.users[0].id);//update user function
                    update.then((updateresponse) => {
                        console.log(updateresponse);
                        }).catch((err) => {
                            console.log(err);
                        })
                } else { //if user doesn't exist
                    let update = newUser(url, user);//createUser(settings.fieldMap, user)
                    update.then((response) => {
                        console.log(response);
                    }).catch((err) => {
                        console.log(err);
                    });
                }
            }) 
    };
};

现在,我想将“更新”变成 Promise,这样我就可以使用 Promise.all() 同时发送多个。这是我尝试过的:

import usersjson from './jsons/users.json';
let promises = [];
if (usersjson.users.length) {
    for (const user of usersjson.users) {
        if (promises.length <= 20) {
            let getuser = getUser(url, user.Id, 'Id');
            getuser.then((data) => {//Make a call to get user by id
                if (data.users.length != 0) { //If user exists
                    let update = new promise ((resolve, reject) => {
                        updateUser(url, user, data.users[0].id).then((response) => {
                            resolve(response);
                        }).catch((err) => {
                            console.log(err)
                        });
                    });
                    promises.push(update);
                } else { //if user doesn't exist
                    let update = new promise ((resolve, reject) => {
                        newUser(url, user).then((response) => {
                            resolve(response);
                        }).catch((err) => {
                            console.log(err);
                        })
                    });
                    psomises.push(update);
                }
            });
        } else {
            await promises.all(update)
            .then ((result) => {
                console.log(result);
                promises = [];
            }).catch(err){
                console.log(err);
            }
        };
    };
};

但我收到一条错误消息:

(node:22016) UnhandledPromiseRejectionWarning: ReferenceError: promise 没有定义 在文件:///C:/xampp/htdocs/NodeAPI/server.js:70:21 在 processTicksAndRejections (internal/process/task_queues.js:97:5) (node:22016) UnhandledPromiseRejectionWarning:未处理的承诺拒绝。这 错误源于在异步函数内部抛出 没有 catch 块,或拒绝未处理的承诺 使用 .catch()。在未处理的承诺上终止节点进程 拒绝,请使用 CLI 标志 --unhandled-rejections=strict(请参阅 https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode)。 (拒绝 ID:1)(节点:22016)[DEP0018] 弃用警告:未处理 不推荐使用承诺拒绝。在未来,承诺拒绝 未处理的将终止 Node.js 进程 非零退出代码。

我的问题是,如何让数组中的 20 个用户同时运行 forEach,而不是一个一个地运行?

【问题讨论】:

  • 你为什么要把awaitthen混在一起?
  • 另外,您不再需要使用.forEachfor( of ) 是很久以前添加到 JavaScript 中的,它适用于任何可迭代对象,包括所有具有 .forEach 函数属性的类型。
  • 因为我显然不知道自己在做什么? :) 我什至不知道为什么我的原始代码需要使用 Promise。我只是被要求这样做。
  • 这段代码比它需要的要复杂得多。我会先以更简单的方式重写它。我不太了解您试图用这段代码完成什么,以及您调用的某些函数做了什么才能建议进行更简单的重写。
  • 另外,你不会“执行承诺”。您执行函数,某些函数可能会返回一个 Promise,它只是一个帮助您监视异步操作的对象。承诺不会“执行”。区别不仅仅是语义,因为它对于理解异步操作和承诺实际发生的事情很重要。

标签: node.js arrays foreach promise


【解决方案1】:
  1. 首先,将处理每个单独的user 值的代码流 移到它自己单独的async 函数中。

    • 由于 async 函数的实际工作方式(因为每个 async function 标记每个异步状态机的边界),在 for 语句中执行并发异步工作实际上并不可行。
  2. for 循环中调用该函数。

  3. 总是更喜欢=== 而不是==

  4. 使用 TypeScript。在没有 TypeScript 的情况下使用 async JavaScript 是一个痛苦的世界,因为您需要跟踪哪些函数返回 Promise&lt;T&gt; 与那些不返回的函数,以及正确解包 Promise&lt;T&gt; 对象。

  5. 始终尽可能拥有自己的 try/catch 语句来包装 async 函数的整个主体,否则您将不得不处理不同 JS 引擎和 JS 代码如何处理抛出的异常和对象的不一致。

import usersjson from './jsons/users.json';

async function updateUsers() {
    
    const promises = [];

    const users = usersjson;
    for( const user of users ) {
        const promise = updateUser( user ); // <-- Note this is *NOT* awaited here.
        promises.push( promise );
    }

    await Promise.all( promises ); // <-- This is where we await everything.
}

async function updateUser( user ) {
    
    try {
        const data = await getUser( url, user.Id, 'Id' );
        if( data.users.length === 0 ) {
            let createResult = await newUser( url, user );
            console.log( "Created new user %o", createResult  );
        }
        else {
            const updateResult = await updateUser( url, user, data.users[0].id );
            console.log( "Update user %o: Result: %o", user.Id, updateResult );
        }
    }
    catch( err ) {
        console.error( "Failed to update (or create) user with UserId %o: %o", user.userId, err );
    }
}


【讨论】:

  • 那么如果我想分块做呢?例如,一次 20-50 个用户?在那种情况下,我怎样才能在 for 循环之外等待?
  • 好的,我设法通过异步所有这些所在的函数来正确地做到这一点。非常感谢!
【解决方案2】:

实现这一点的最简单方法是在 foarch 方法中,将所有的 Promise 引入一个数组中,然后调用它们,然后使用 Promise.all 等到一切都完成。

let promiseArray = []
array.forEach(x => {
      // Do whatever you need
     promiseArray.push(updateUser(...))
     // Push only the promise without the 'then'
     // You are going to handle the response or 
     // the errors later  

})
const promiseResponses = await Promise.all(promiseArry)
// promiseResponses is an array of responses
// like promiseResponse[0] 

【讨论】:

  • 谢谢!但是,当我尝试使用此方法时,“Promise.all”之前的“await”出现错误“SyntaxError: Unexpected reserved word”。我不能在“forEach”循环中使用“await”,这会阻止我设置一个计数器(我想一次推送大约 50 个承诺,所以在每次“推送”之后我检查数组的长度和如果是 20,我使用“Promise.all”函数。
猜你喜欢
  • 2016-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-12
  • 1970-01-01
  • 2018-07-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多