Узел JS Promise затем выполняется блок до разрешения обещания - PullRequest
0 голосов
/ 15 апреля 2019

Простой путь к коду, который лучше объяснить с помощью маркеров

  1. Вызов API
  2. Вызов в БД
  3. Результатом является список объектов
  4. Внутри блока then вызовите DB для каждого объекта, чтобы увлажнить дочерние элементы
  5. Внутри другого блока then.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 голосов
/ 15 апреля 2019

Чтобы шаг 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).

0 голосов
/ 15 апреля 2019

У меня есть несколько комментариев по поводу вашего кода:

  1. вы делаете мутацию, что является плохой практикой, функция getChildren принимает любой тип результата, а затем вносит в него некоторые изменения, например

result.children = []

Избегайте использования any и попробуйте определить тип

в вашем коде, потому что вы делаете мутацию, поэтому вам даже не нужно возвращать результат, потому что исходный объектуже изменено, но, как я упоминал ранее, вам следует избегать мутаций.

Основная проблема, которую шаг 5 выполняет перед шагом 4, состоит в том, что getChildren не возвращает обещание назад, я внес некоторые изменения вВаш код для размещения обещания.

      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!")
      })
    }
0 голосов
/ 15 апреля 2019

Шаг 5 происходит до того, как шаг 4 (getChildren функция) завершается, потому что getChildren не возвращает обещание.Если изменить его на следующее, это может решить проблему:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...