簡體   English   中英

如何在NodeJs中發送回響應之前等待循環完成?

[英]How to wait for a loop to finish running before sending back a response in NodeJs?

我試圖在對URL的GET請求之后將對象數組發送回去,但是我不知道如何構造邏輯,因此返回數組在發送給客戶端之前會完全填充。

下面是我的服務器端代碼,用於響應請求。 我之前在代碼中使用過passport.js來創建登錄門戶和用戶對象。 我正在嘗試從發出請求的用戶那里獲取“連接”數組,並將其發送回帶有連接名稱和圖片的對象數組。 我知道以下代碼在語法上是不正確的,但這是我要完成的工作的概述。 我嘗試過以回調的方式進行操作,但這一直使我陷入困境,因為我無法找出正確的邏輯。

router.get('/data', function(req, res, next) {
    var IdArr = req.user.connections;

    var retArr = [];

    function getUsers() {
        for (i = 0; i < IdArr.length; i++) {
            User.getUserById(IdArr[i], function(err, patient) {
                retArr[i] = {name:patient.name, pic:patient.profileImage};
            });
        }
    }

    function getDataAndSend() {
        function(getUsers(), function sendRes() { // I know this is incorrect syntax
            console.log(retArr);
            res.json(retArr);
        });
    }

    getDataAndSend();
});

首先,您應該聲明i ,並且在進行聲明時應使用block-scope( let ),以便嵌套的回調函數將使用相同的變量。

您可以檢查retArr中已經檢索了多少條目,並在知道所有內容后調用res.json

router.get('/data', function(req, res, next) {
    var IdArr = req.user.connections;
    var retArr = [];
    for (let i = 0; i < IdArr.length; i++) {
        User.getUserById(IdArr[i], function(err, patient) {
            retArr[i] = {name:patient.name, pic:patient.profileImage};
            if (Object.keys(retArr).length === IdArr.length) res.json(retArr);
        });
    }
});

我認為處理這些問題的最簡單方法是使用Promises。 任何以回調方式編寫的異步函數(例如,此User.getUserById)都可以轉換為返回承諾的函數。 您只需將呼叫包裝在一個新的Promise中,並在完成后解決。

說你的情況。

function promiseGetById(id) {
    return new Promise((resolve, reject) =>
        User.getUserById(id, (err, pat) => resolve(pat))
    );
}

然后像

Promise.all(IdArr.map(id => promiseGetById(id))).then(arr =>
    res.json(
        arr.map(patient => ({ name: patient.name, pic: patient.profileImage }))
    )
);

或者,如果您不喜歡諾言,則可以通過擁有一個計數器或在每個回調中遞增的東西來實現它,然后在計數器為正確值時在回調中添加res.json。

更改所有函數邏輯以返回承諾,並使用async/await來使代碼清晰。

const getUserById = (id) => {
  return new Promise((resolve, reject) => {
    User.getUserById(IdArr[i], function(err, patient) {
      resolve({name:patient.name, pic:patient.profileImage});
    });
  });
}

const getAllUsers = async(idArr) => {
  const retArr = [];

  // for...of loop to await without continuing the loop
  // but this will execute only sequentially
  for (let id of idArr) {
    const ret = await getUserById(id);
    retArr.push(ret);
  }

  // for parallel execution, use Promise.all()
  await Promise.all([...idArr.map(id => getUserById(id))]);

  return retArr;
}

router.get('/data', async (req, res, next) => {
  var IdArr = req.user.connections;
  var retArr = await getAllUsers(IdArr);

  console.log(retArr);
  res.json(retArr);
});

您似乎正在嘗試為不那么復雜的算法提取許多函數的方法。 以下代碼初步提取了請求所需的信息。 然后,它填充響應所需的數組並簡單地發送它。

router.get('/data', (req, res, next) => {
    const idArray = req.user.connections;

    let responseArray = [];

    // loop to populate responseArray
    for (let id of idArray) {
        User.getUserById(id, (err, patient) => {
            // add to the end of the array the patient informations
            responseArray.push({
                name: patient.name,
                pic: patient.profileImage
            });
        });
    }

    // send back responseArray
    res.json(responseArray);
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM