【问题标题】:Attempting to use async/await over an array function尝试对数组函数使用 async/await
【发布时间】:2019-10-29 16:32:08
【问题描述】:

我正在尝试简化 Express 后端的测试脚手架。我不想多次调用单个记录插入例程,这在检查结果时似乎存在同步问题,我想使用数组一个接一个地执行数据库插入。

这是我到目前为止所拥有的......但我似乎在不知何故搞砸了异步等待。测试失败,因为我得到了 0 个身体长度,也许还有一个插入。有什么想法我哪里出错了吗?


async function asyncForEach (array, callback) {
  for (let index = 0; index < array.length; index++) {
    await callback(array[index], index, array);
  };
}

async function insertTemplates(myTemplatesArray) {
  const client = new Client(dbConfig);
  client.connect();
  await asyncForEach(
    myTemplatesArray,
    async (myTemplate) => {
      let { name, status, version } = myTemplate;
      await client.query(
        SQL`INSERT INTO templates (name, status, version )
        VALUES (${name}, ${status}, ${version})`)
        .catch( err => console.error(err) );
    });
  client.end();
}

function randomTemplate() {
  const template = {
    name: faker.internet.userName(),
    status: faker.hacker.phrase(),
    version: String(faker.random.number())
  };
  return template;
}

function clean_db(){
  const client = new Client(dbConfig);
  client.connect();
  client.query(
    `TRUNCATE TABLE "templates";
    ALTER SEQUENCE "templates_id_seq" RESTART WITH 1;`)
    .catch( err => { console.error(err); } )
    .then( () => client.end() );
}

describe('When there are 1 or more records in the table', () => {

    const templ1 = randomTemplate();
    const templ2 = randomTemplate();
    const templ3 = randomTemplate();

    beforeEach(async () => {
      await clean_db();
      await insertTemplates([templ1,templ2,templ3]);
    });

    afterEach(async () => {
      await clean_db();
    });

    test('It should respond with a 200 status', async done => {
      const response = await template(app).get('/templates');
      expect(response.status).toBe(200);
      done();
    });

    test('It should respond with an JSON array of records', async done => {
      const response = await template(app).get('/templates');
      expect(response.body.length).toBe(3);
      done();
    });

    test('It should respond with the correct records', async done => {
      templ1.id = 1;
      templ2.id = 2;
      templ3.id = 3;

      const response = await template(app).get('/templates');
      expect(response.body).toStrictEqual([templ1,templ2,templ3]);
      done();
    });
  });
});

【问题讨论】:

  • VALUES (${name}, ${status}, ${version}) 似乎没有被转义,我无法想象插入工作。
  • 侧节点:可以去掉async done =&gt; {done();,换成:async () =&gt; {
  • VALUES (${name}, ${status}, ${version}) 在反引号中,我正在使用“sql-template-strings”包,因此SQL 前缀/调用,我不得不说这是一个相当不错的包.
  • 谢谢,下次一定要注意后面勾前面的东西。

标签: arrays node.js async-await


【解决方案1】:

我相信您的测试未按预期工作的原因是您破坏了 clean_db().. 中的承诺链。也许还有其他一些功能。这在使用 Promise 时很容易做到!

我建议确保 clean_db 返回一个承诺,例如像这样:

function clean_db(){
    const client = new Client(dbConfig);
    client.connect();
    // return promise to keep chain intact.
    return client.query(
        `TRUNCATE TABLE "templates";
        ALTER SEQUENCE "templates_id_seq" RESTART WITH 1;`)
        .catch( err => { console.error(err); } )
        .then( () => client.end() );
}

我假设 client.end() 返回了一些东西。这应该会导致 clean_db() 返回一个承诺,所以 await 调用实际上会等待。

我会为 insertTemplates 做同样的事情,例如返回 client.end() 的结果。

async function insertTemplates(myTemplatesArray) {
  const client = new Client(dbConfig);
  client.connect();
  await asyncForEach(
    myTemplatesArray,
    async (myTemplate) => {
      let { name, status, version } = myTemplate;
      // Return promise to calling proc.
      return client.query(
        SQL`INSERT INTO templates (name, status, version )
        VALUES (${name}, ${status}, ${version})`)
        .catch( err => console.error(err) );
    });
    return client.end();
}

另外,请确保您传递给 asyncForEach 的 回调 返回一个承诺。我不确定它是否会这样做。

【讨论】:

  • 特里,您先生是一位绅士和一位学者。 CleanDB() 没有返回承诺显然是承诺 - 只是那个变化,测试第一次通过。非常感谢!
  • 很高兴听到这个消息,我自己也曾在同一个地方被抓过几次 :-) ...
猜你喜欢
  • 2023-03-12
  • 1970-01-01
  • 2017-07-19
  • 2017-04-14
  • 2020-08-01
  • 2021-08-06
  • 2016-01-22
相关资源
最近更新 更多