代码之家  ›  专栏  ›  技术社区  ›  Multitut

Nodejs和Mongoose:Await stops循环

  •  0
  • Multitut  · 技术社区  · 5 年前

    这是我的代码:

    const csv = require('csv-parser');
    const fs = require('fs');
    const Customer = require('../../app/models/Customers');
    
    const projects = [];
    
    const processRecords = async () => {
      try {
        const usableProjects = projects.filter((project) => project['cust_number customer']);
        const customerNames = [...new Set(usableProjects.map((item) => item['Parent Name']))];
        await customerNames.forEach(async (customerName) => {
          console.log('Point 1');
          const existingCustomer = await Customer.find({Name: customerName});
          console.log('Point 2'); //<======= THIS CODE IS NEVER REACHED
          if (existingCustomer.length > 0) {
            console.log(`${customerName} already exists. Skipping...`);
            return;
          }
          const customerRecord = usableProjects.find((project) => project['Parent Name'] === customerName);
          const newCustomer = {
            Name: customerName,
            Source: 'CSV',
            Initials: customerRecord.Initials,
            Code: customerRecord.Codename,
          };
          const newCustomerRecord = await Customer.create(newCustomer);
          if (newCustomerRecord) {
            console.log(`Customer ${newCustomerRecord._id} created`);
          }
        });
      } catch (err) {
        console.log(err);
      }
    };
    
    fs.createReadStream('customer_table.csv')
      .pipe(csv())
      .on('data', async (data) => projects.push(data))
      .on('end', async () => {
        processRecords();
      });
    

    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    Point 1
    

    我知道这可能与同步/异步代码没有被我更正有关。但我没能修好。提前谢谢。

    2 回复  |  直到 5 年前
        1
  •  1
  •   marc_s HarisH Sharma    5 年前

    try-catch 在一个 Customer.find() (为了清楚起见,我将简化您的代码。我会替换 客户。查找() 具有 f() )

    async function success() { return "Hurrah!" }
    async function failure() { throw new Error("Oops!") }
    
    const customerNames = [1, 2, 3]
    
    const processRecords1 = async (f) => {
        try {
            await customerNames.forEach(async (customerName) => {
                try {
                    console.log('Point 1');
                    const existingCustomer = await f()
                    console.log('Point 2', existingCustomer);
                    // ...
                } catch (err) {
                    console.log('Point 3', err);
                }
            });
        } catch (err) {
            console.log('Point 4', err);
        }
    };
    setTimeout(() => processRecords1(success), 0);
    

    Point 1
    Point 1
    Point 1
    Point 2 Hurrah!
    Point 2 Hurrah!
    Point 2 Hurrah!
    

    如你所见,如果 f = success 到达“点2”。所以这是第一个问题:你的 客户。查找() 失败,你看不到异常。 让我们试着从 为了证明这一点。。。

    setTimeout(() => processRecords1(failure), 100);
    

    输出:

    Point 1
    Point 1
    Point 1
    Point 3 Error: Oops!
    Point 3 Error: Oops!
    Point 3 Error: Oops!
    

    是的,如果 如果失败,我们就永远到不了“第二点”。但现在我们确实看到了一个错误,在“第3点”。所以我们可以停在这里。

    processRecords() 到第四点。 forEach() 不返回值。我们试试看 map()

    const processRecords2 = async (f) => {
        try {
            await customerNames.map(async (customerName) => {
                console.log('Point 1');
                const existingCustomer = await f()
                console.log('Point 2', existingCustomer);
                // ...
            });
        } catch (err) {
            console.log("Point 4", err);
        }
    };
    setTimeout(() => processRecords2(failure), 200);
    

    Point 1
    Point 1
    Point 1
    Uncaught (in promise) Error: Oops!
    Uncaught (in promise) Error: Oops!
    Uncaught (in promise) Error: Oops!
    

    运气不好。是因为 地图() 确实返回一个值,但它是 Array ,不是 Promise . 你不能 await 一系列的承诺,但是你可以使用 Promise.all() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

    const processRecords3 = async (f) => {
        try {
            await Promise.all(customerNames.map(async (customerName) => {
                console.log('Point 1');
                const existingCustomer = await f()
                console.log('Point 2', existingCustomer);
                // ...
            }));
        } catch (err) {
            console.log("Point 4", err);
        }
    };
    setTimeout(() => processRecords3(failure), 300);
    

    Point 1
    Point 1
    Point 1
    Point 4 Error: Oops!
    Point 4 Error: Oops!
    Point 4 Error: Oops!
    

    就这样。替换 await customerNames.forEach(...) await Promise.all(customerNames.map(...) 你可以走了。

        2
  •  1
  •   Kevin N.    5 年前

    我同意@JaromandaX,forEach不知道承诺,也不支持async/await。使用 map

        3
  •  1
  •   Pubudu Dodangoda    5 年前

    阵列 forEach map 是一条路。但是,请注意,您应该将其与 Promise.all

    async function example(arr) {
      await Promise.all(
        // Assume item.fetch() returns a promise
        arr.map(item => item.fetch())
      );
    }
    

    现在,这将并行运行所有item.fetch调用。在大多数情况下,这是首选方法。但是,如果要以串行方式运行item.fetch调用,则应改用for循环。

    async function example(arr) {
      for (let item of arr) {
        await item.fetch();
      }
    }