node.js와 redis를 사용해서 backend를 구성하였다. map에 hget을 활용하여 데이터를 조회하는 작업을 하던중 비동기로 인해 문제가 발생했다.
function getTestDetail(testList) {
let testDetailList = new Array();
Promise.all(testList.map(async (testID) => {
let data = await client.hgetall(`test_${testID}`, (err, test) => {
console.log(test)
return test
});
console.log('datat',data)
}));
return testDetailList
};
...
app.get("/:id", async (req, res, next) => {
try {
const testList = [1, 2, 5];
const testDetailList = await getTestDetail(testList);
// console.log(testDetailList,4444)
res.json(testDetailList)
} catch (e) {
return next(e)
}
})
'/:id
path로 요청이 들어오면 id에 해당하는 유저의 문제번호를 확인하고 번호에 맞는 데이터를 보내줘야한다. 여기서 문제는 javascript가 map을 통해 데이터를 조회하는 과정을 기다려주지 않는다는 점이었다.
그래서 데이터를 console.log() 찍게되면 undefine
,null
,[]
과 같은 결과만 나오게 되었다.
const { promisify } = require("util");
먼저 util 모듈에서 promisify를 불러옵니다.
const client = redis.createClient()
...
const getallAsync = promisify(client.hgetall).bind(client);
const getAsync = promisify(client.hget).bind(client);
const hgetAsync = promisify(client.get).bind(client);
const asmembers = promisify(client.smembers).bind(client)
const ahkeys = promisify(client.hkeys).bind(client)
return getAsync('foo').then(function(res) {
console.log(res);
}));
async myFunc() {
const res = await getAsync('foo');
console.log(res);
}
대표 2가지의 비동기 호출방법이 존재한다. 나는 여기서 async/await를 활용해서 원하는 데이터를 조회하고 가공해서 response 하였다.
Priomise.all()
은 메서드는 순회 가능한 객체에 주어진 모든 프로미스가 이행한 후, 혹은 프로미스가 주어지지 않았을 때 이행하는 Promise를 반환합니다. 주어진 프로미스 중 하나가 거부하는 경우, 첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부합니다.
여기서 봐야하는 점은 "순서대로 실행되지만 앞의 함수가 완료되는 것을 기다리지 않는다"는 점이다. 마지막으로 완료되는 함수까지 기다린 후 값을 반환한다.반환순서는 실행 순서와 동일하게 준다.
즉, Promise.all()
은 비동기 작업을 병렬로 실행하고 결과를 배열로 빠르게 확인할 수 있는 함수라고 생각하면 된다.
app.get("/:id", async (req, res, next) => {
const id = req.params.id;
const getTest = await getallAsync(`users_${id}`)
const {test = ""} = getTest || {};
const testIDs = test.split(',').map(ele => parseInt(ele));
const testList = [];
await Promise.all(testIDs.map(async (testID) => {
const data = await getallAsync(`test_${testID}`)
testList.push(data)
}))
return res.status(200).json({data: testList});
});
+) 보통 비동기처리를 하게되면 try catch로 에러처리를 하게된다. 하지만 그렇게 되면 중간에 에러가 발생할 때 디버깅할 때 어려움이 발생하게 된다. 그래서 개발단계에서는 최대한 코드에서 보안코드 작성으로 에러를 처리하고 QA까지 했는데도 찝찝하게 에러가 걱정된다면 try catch를 도입해 에러를 처리하자!
참고)
https://flaviocopes.com/node-promisify/