然后,节点JS Promise会在承诺解析之前阻塞执行

时间:2019-04-15 00:35:22

标签: node.js promise

简单的代码路径,最好用要点解释

  1. API调用
  2. 致电数据库
  3. 结果是对象列表
  4. 在then块中,对每个对象进行DB调用以为孩子补水
  5. 在另一个内部,然后阻止res.send(水化对象)

问题

步骤5在步骤4完成之前发生(下面的代码)

//api endpoint
router.post('/get-data', getObjects);

export const getObjects: express.RequestHandler = (req, res) => {
    queryContainer(containerId, querySpec)
    .then((result) => {
        return getChildren(result, req.body.criteria);
    })
    .then((result) => {
        res.send(result);
    });
}

export async function queryContainer(containerId, querySpec) {
    const { result: results } = await client.database(databaseId).container(containerId).items.query(querySpec, {enableCrossPartitionQuery: true}).toArray()
    .catch( (error) => {
        console.log("Error! ", error);
    });
    return results;
}

function getChildren(result: any, criteria: any) {
    if(criteria) {
        result.children = [];
        var actions = result
                        .map(result => result.element)
                        .map(dbCallToGetChildren);
        var results = Promise.all(actions);
        results.then(children => {
            result.children.push(...children)
            return result;
        });
    } 

    return result;
}

export const dbCallToGetChildren = (async function (username) {
    const querySpec = {
        query: "SELECT * FROM root r WHERE r.userName=@userName",
        parameters: [
            {name: "@userName", value: username}
        ]
    };
    queryContainer(containerId, querySpec)
    .then((results) => { 
        return results;
    })
    .catch((error) => {
        console.log("Error " + error);
        return Promise.resolve;
    });
});

3 个答案:

答案 0 :(得分:0)

第5步发生在第4步(getChildren函数)完成之前,因为getChildren没有返回Promise。将其更改为以下内容可能会解决问题:

function getChildren(result: any, criteria: any) {
  return new Promise(resolve => {
    if(criteria) {
        result.children = [];
        var actions = result
                        .map(result => result.element)
                        .map(dbCallToGetChildren);
        var results = Promise.all(actions);
        results.then(children => {
            result.children.push(...children)
            resolve(result);
        });
    } else {
      resolve(result);
    }
  });
}

results.then(children => { ... }内现在有resolve(result);,以确保return getChildren(result, req.body.criteria);调用中的queryContainer语句在Promise解决之前不会完成。

答案 1 :(得分:0)

为了使第4步在执行第5步之前完全完成,我们需要说明通过getChildren的每个代码路径。

这意味着我们应该对此进行更改:

function getChildren(result: any, criteria: any) {
    if(criteria) {
        result.children = [];
        var actions = result
                        .map(result => result.element)
                        .map(dbCallToGetChildren);
        var results = Promise.all(actions);
        results.then(children => {
            result.children.push(...children)
            return result;
        });
    } 
    return result;
}

进入以下内容(注意代码注释):

function getChildren(result: any, criteria: any) {
    if(criteria) {
        result.children = [];
        var actions = result
                        .map(result => result.element)
                        .map(dbCallToGetChildren);
        var results = Promise.all(actions);
        return results.then(children => { // returns a promise 
            result.children.push(...children)
            return result;
        });
    } 
    return Promise.resolve(result); // returns a promise
}

重要的是return,否则此行中的代码将以异步方式执行(这不能保证第4步将在第5步开始之前完成)。

答案 2 :(得分:0)

我对您的代码有几点评论:

  1. 您正在做突变,这是一个不好的做法,getChildren函数接受任何结果类型,然后像
  2. 那样对其进行一些更改

result.children = []

  1. 避免使用any并尝试定义类型

  2. 在您的代码中是因为您正在进行突变,所以您甚至不需要返回结果,因为原始对象已被更改,但是正如我之前提到的,您应该避免突变。

  3. 在第4步之前执行第5步的主要问题是getChildren不会返回promise,我对您的代码进行了一些更改以适应promise。

      function getChildren(result: any, criteria: any): Promise<any> {
      return new Promise((resolve, reject) => {
        if (criteria) {
          result.children = []
          const actions = result
            .map(item => item.element)
            .map(dbCallToGetChildren)
          Promise.all(actions).then(children => { // returns a promise
            result.children.push(...children)
            return resolve("successfully is processed!")
          })
        }
        reject("invalid criteria!")
      })
    }