【问题标题】:Function work incorrectly when using promise in node js在节点 js 中使用 promise 时函数工作不正确
【发布时间】:2018-12-05 23:38:44
【问题描述】:

我有这样的路线:

router.get('/:projectid/, (req, res) => {
    testCase.getTestCaseDetail(req.params.projectid, req.params.testcaseid, req.params.snapshotId).then(testcaseData => {
      res.render('testCaseService', {
        title: 'Page',
        testcase: testcaseData,
        layout: 'project_layout',
      });
    });
  });

在处理函数中,我有 getTestCaseDetail 函数:

function getTestCaseDetail(projectId, id, snapshotId) {
  let testCaseId = parseInt(id);
  return new Promise(((resolve, reject) => {
    return testCaseSchema.aggregate([
      { $match: { 'projectId': projectId, 'testCaseId': testCaseId } },
      {
        $lookup: {
          from: snapshotInfoSchema.collection.collectionName,
          localField: testCaseObj.SERVICE_ID,
          foreignField: 'artifacts.id',
          as: 'services',
        },
      },
      { $unwind: '$services' },
      {
        $match: {
          'services.snapshot.id': snapshotId,
        }
      }
    ]).then(testCaseResult => {
      resolve(addTestCasesV2(testCaseResult, snapshotId));
    })
      .catch(err => {
        reject(err);
      })
  }));
}

addTestCasesV2函数

const addTestCasesV2 = function (testcases, snapshotId) {
  const result = [];
  let serviceTypeMapping;
  let serviceName;
  let testCase = {
    id: '',
    testCaseId: '',
    name: '',
    serviceName: '',
    serviceType: '',
    modifiedAt: '',
    testScripts: '',
    snapshotId: '',
    services: '',
    inputs: [],
    outputs: [],
  };
  let promiseInputResults, promiseOutputResults;
  const testcasesList = lodash.map(testcases, (tc) => {
    const artifacts = lodash.map(tc.services.artifacts, (art) => {
      if (art.id === tc.service_id) {
        serviceTypeMapping = art.processType.serviceTypeName;
        serviceName = art.name;
        if (!commonUtil.isUndefined(art.processParameters)) {
          if (!commonUtil.isUndefined(art.processParameters.input)) {
            promiseInputResults = lodash.map(art.processParameters.input, (ip) => {
              let classId = commonUtil.getArtifactId(ip.classId);
              return objectType.getObjectTypeByClassId(snapshotId, classId)
            });
          }

          if (!commonUtil.isUndefined(art.processParameters.output)) {
            promiseOutputResults = lodash.map(art.processParameters.output, (ip) => {
              let classId = commonUtil.getArtifactId(ip.classId);
              return objectType.getObjectTypeByClassId(snapshotId, classId)
            });
          }
        }
        testCase.id = tc.testCaseId;
        testCase.testCaseId = tc.testCaseId;
        testCase.name = tc.name;
        testCase.serviceName = serviceName;
        testCase.serviceType = serviceTypeMapping;
        testCase.modifiedAt = tc.modifiedAt;
        testCase.testScripts = tc.testScripts;
        testCase.snapshotId = snapshotId;
        testCase.services = tc.services;

        Promise.all(promiseInputResults).then(inputItems => {
          return testCase.inputs = inputItems;
        });

        Promise.all(promiseOutputResults).then(outputItems => {
          return testCase.outputs = outputItems;
        });

      }
    });
  });
  return testCase;
};

输入/输出是一个项目列表,如下所示: 输入:[ { 名称:“test1”, 类型:“字符串” }, { 名称:“test2”, 类型:“数字” }, ]

我的 Promise 生命周期有问题,这是当前流程 1. 路线 2.函数getTestCaseDetail 3. 解决(addTestCasesV2(testCaseResult, snapshotId)); 4. addTestCasesV2 ==> 返回 testCase 但没有转到 2 个 promise.all 函数 5. 解决(addTestCasesV2(testCaseResult, snapshotId)); 6. 路线 7.返回2个promise.all函数 8. 结束于 return testCase.outputs = outputItems;

请看图片更详细的流程(白色数字是当前流程,橙色数字是我的预期流程)

请给我建议。非常感谢。

【问题讨论】:

  • objectType.getObjectTypeByClassId() 返回什么?它返回一个值还是一个承诺?是同步的还是异步的?
  • 而且,getTestCaseDetail() 包含一个 Promise 反模式。不需要在该函数中将其包装在 new Promise() 中。只需执行return testCaseSchema.aggregate(...).then(...)。回报你已经拥有的承诺。

标签: javascript node.js promise


【解决方案1】:

您的代码似乎不正确。如果testcases 是一个包含多个项目的数组,您的lodash.map 回调将被调用testcases.length 时间。每次覆盖之前回调中分配的testCase.id

无论如何,我已经更正了您的代码,使其按您想要的运行顺序运行。我已经在各个地方登录==step== 以寻求您的帮助。

第一个功能:

function getTestCaseDetail(projectId, id, snapshotId) {
    let testCaseId = parseInt(id);
    return new Promise(((resolve, reject) => {
        return testCaseSchema.aggregate([
            { $match: { 'projectId': projectId, 'testCaseId': testCaseId } },
            {
                $lookup: {
                    from: snapshotInfoSchema.collection.collectionName,
                    localField: testCaseObj.SERVICE_ID,
                    foreignField: 'artifacts.id',
                    as: 'services',
                },
            },
            { $unwind: '$services' },
            {
                $match: {
                    'services.snapshot.id': snapshotId,
                }
            }
        ]).then(testCaseResult => {
            console.log('=======STEP 1=======');
            resolve(addTestCasesV2(testCaseResult, snapshotId));//=======STEP 2=======
            console.log('=======STEP 5=======')

        })
            .catch(err => {
                reject(err);
            })
    }));
}

第二个功能

const addTestCasesV2 = function (testcases, snapshotId) {
    console.log('=======STEP 2=======')
    const result = [];
    let serviceTypeMapping;
    let serviceName;
    let testCase = {
        id: '',
        testCaseId: '',
        name: '',
        serviceName: '',
        serviceType: '',
        modifiedAt: '',
        testScripts: '',
        snapshotId: '',
        services: '',
        inputs: [],
        outputs: [],
    };
    let promiseInputResults, promiseOutputResults;

    return Promise.resolve()
        .then(()=>{
            console.log('=======STEP 3=======');
            const testcasesList = lodash.map(testcases, (tc) => {
                const artifacts = lodash.map(tc.services.artifacts, (art) => {
                    if (art.id === tc.service_id) {
                        serviceTypeMapping = art.processType.serviceTypeName;
                        serviceName = art.name;
                        if (!commonUtil.isUndefined(art.processParameters)) {
                            if (!commonUtil.isUndefined(art.processParameters.input)) {
                                promiseInputResults = lodash.map(art.processParameters.input, (ip) => {
                                    let classId = commonUtil.getArtifactId(ip.classId);
                                    return objectType.getObjectTypeByClassId(snapshotId, classId)
                                });
                            }

                            if (!commonUtil.isUndefined(art.processParameters.output)) {
                                promiseOutputResults = lodash.map(art.processParameters.output, (ip) => {
                                    let classId = commonUtil.getArtifactId(ip.classId);
                                    return objectType.getObjectTypeByClassId(snapshotId, classId)
                                });
                            }
                        }
                        testCase.id = tc.testCaseId;
                        testCase.testCaseId = tc.testCaseId;
                        testCase.name = tc.name;
                        testCase.serviceName = serviceName;
                        testCase.serviceType = serviceTypeMapping;
                        testCase.modifiedAt = tc.modifiedAt;
                        testCase.testScripts = tc.testScripts;
                        testCase.snapshotId = snapshotId;
                        testCase.services = tc.services;


                        /*=======FOLLOWING IS NOT REQUIRED=======*/
                        // Promise.all([promiseOutputResults]).then(outputItems => {
                        //     return testCase.outputs = outputItems;
                        // });

                    }
                });
            });
            return Promise.all([promiseInputResults,promiseOutputResults]);
        })
        .then(inputItems => {//array of resolved values
            console.log('=======STEP 4=======');
            testCase.inputs = inputItems[0];
            testCase.outputs = inputItems[1];
            return testCase;
        })
};

现在您可以使用以下方法从第一个函数中提取测试用例:

getTestCaseDetail(myProjectId, id, mySnapshotId)
    .then(testCase=>console.log(testCase))

JSfiddle 供您理解。

【讨论】:

  • 谢谢你的建议,我有一些问题:1.这个块代码“.then(inputItems =>....”应该放在Promise.all之后,对吗?2.替换后,我尝试运行,但结果在console.log(testCase)中未定义
  • @PhạmQuốcBảo 1. Promise.all([p1,p2) 是一个返回新承诺的函数。这个 Promise 解析为 [v1,v2]。所以你使用 then() 链接到这个 Promise,就像任何其他 Promise 一样。有关更多详细信息,请参阅此答案here
  • @PhạmQuốcBảo 2.您可以在第 4 步使用 console.log() 来检查您从 inputItems 获得的值吗?
  • 这里是日志号和错误:===STEP 1==== =======STEP 2======= ===STEP 5==== =======步骤 3======= =======步骤 4======= 内部/进程/warning.js:18 (node:8508) UnhandledPromiseRejectionWarning: TypeError:无法读取未定义的属性“0”
  • @PhạmQuốcBảo 没有。 Promise.all() 需要一个承诺数组。如果只有一个 Promise,则不需要 Promise.all。 promiseInputResults.then(inputItems => { testCase.inputs = inputItems; return promiseOutputResults }).then(outputItems => { testCase.outputs = outputItems; return testCase; });
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-16
  • 1970-01-01
  • 1970-01-01
  • 2019-02-12
  • 2020-02-01
  • 2021-03-21
  • 2018-05-17
相关资源
最近更新 更多