js로 프로그램을 짜다보면 어떠한 모듈(주로 async한 작업을 해주는 모듈)을 이용한 함수를 내가 정의했을 때, 리턴값을 원활히 전달하기 쉽지 않은 경우가 자주 있습니다.
● 잘못된 예
예를 들어 어떠한 사이트의 헤더를 긁어오는 작업을 한다고 했을 때
아래의 코드와 같이 작업하면 리턴값을 얻을 수 없습니다.
var request=require("request")
function getHeaders(url){
request(url, function(err, res, body){
// console.log(res.headers)
return res.headers
//함수 내부의 request 함수 호출에 전달한 콜백이 완료되면 리턴 값을 전달하고 싶은 것임.
//하지만 이렇게 하면 예상했던 대로의 리턴값을 얻을 수 없다.
})
}
console.log(getHeaders("http://senticoding.tistory.com"))
● 해결책 1) Promise이용
우선 async적 작업을 마친 뒤 결과값 리턴을 위해 Promise를 이용할 경우 "함수 작업을 실행 한 뒤 리턴을 해야지"식의 방식이 아닌
"리턴해야지. 이거 끝나고" 이런 식으로 작업을 해야합니다.
무슨 말인지 와닿지 않을 수 있습니다. 쉽게 말하자면
request(url, function( ... ){
... asynce적 작업 ...
return ...
}) //이런 식으로는 불가능하다
return new Promise(resolve=>{
request(url, function( ... ){
...async적 작업 수행
resolve(리턴값)
})
}) //이런 식으로 해야한다!
즉 먼저 프로미스를 생성하고 프로미스의 콜백에서 async적 작업을 넣어주고 resolve를 해주면 됩니다.
● 해결책 1) 1. Promise를 then()으로 받기
var request=require("request")
function getHeaders(url){
return new Promise(resolve=>{
request(url, function(err, res, body){
// console.log(res.headers)
resolve(res.headers )
})
})
}
getHeaders("http://senticoding.tistory.com")
.then(function(result){
console.log(result)
})
nodejs는 기본적으로 단일 스레드인 프레임웍이지만, then은 쉽게 말해 하나의 스레드를 생성시키는 개념이라고 볼 수 있습니다. 리턴받은 promise를 then속의 콜백 함수에게 인자로 전달해주게 됩니다.
● 해결책 1) 2. Promise를 async await 이용해서 작업하기
var request=require("request")
function getHeaders(url){
return new Promise(resolve=>{
request(url, function(err, res, body){
// console.log(res.headers)
resolve(res.headers )
})
})
}
(async ()=>{
console.log(await getHeaders("http://senticoding.tistory.com"))
})()
async/await 는 좀 더 직관적이에요. 우선 await는 말그대로 어떠한 작업을 기다린다는 말입니다. 하지만 await 예약어를 사용하기 위해선 async 함수 안에서만 사용할 수 있다. 처음에는 이 부분이 헷갈릴 수 있습니다. async 함수란 해당 함수가 종료되고서 다음 작업이 이루어 지게되는 함수가 아니라, 해당 함수의 작업을 백그라운드에 넘기고 다음 작업을 수행시키는 함수입니.
즉 async 함수의 작업 자체는 순서에 오히려 구애받지 않는 듯 하지만 함수 내부에서 순서를 좀 더 명확히 하기 위해선 await를 써줘야하는데, 그 함수는 async여야한다는 것입니다.
설명이 좀 장황하긴 했지만, 그냥 쉽게 얘기하자면 await를 쓰기위해선 async함수 내에서만 사용이 가능하다는 것입니다. 따라서 위의 예제 코드에서 arrow function과 즉시 실행 함수 형식을 이용해 간단히 표현해보았습니다.
● 해결책 2) async적 작업을 수행하는 함수가 아닌 sync적 작업을 수행하는 함수를 사용한다.
request 모듈에서는 마땅한 예시가 없지만 주로 쓰이는 fs모듈의 경우에는 예시가 생각이 나 적어볼게요.
예를 들어 fs.writeFile 작업을 수행한뒤 어떠한 값을 리턴해주고 싶은 경우가 있다고 합시다.
fs.writeFile(location, data, function(err){ }) 를 이용하는 경우 위 해결책 1)에서 내가 서술한 대로 하면 됩니다.
허나 이번엔 해결책 2)로 fs.writeFileSync(location, data)를 이용해볼게요. 즉 writeFile같은 async function이 아닌 sync function을 이용하면 됩니다. 그리고 이게 사실 가장 간단한 방법이에요. ( 그러나 비동기적 처리가 장점인 nodejs 에게 무조건 옳고 좋은 방법은 아닐 수 있음 )
▽코드예제
function saveData(){
fs.writeFileSync("test.txt", "hello")
console.log("in saveData")
return true
}
console.log("before")
saveData()
console.log("after")
● 마치며
사실 C나 JAVA 및 기타 언어를 거치며 이 내용은 Promise 자체가 아니라 그러한 개념을 본 적이 거의 없어서 javascript만의 특이한 개념인 것 같아요. 그래서 js에 익숙치 않으면 어렵게 느껴질 수도 있는데, 위의 내용들만 다 터득해도 js에서 작업의 수행 순서 및 프로미스 리턴 등등에 대해서는 어려운 점은 없을 것이에요. 여러개의 작업을 동기적으로 수행하고 끝으로 Promise.all등을 이용하는 경우가 아닌 한은.
'Node.js' 카테고리의 다른 글
[오픈 API] nodejs를 이용해 버스 도착 정보 얻기 - 2. 코드 (0) | 2019.02.24 |
---|---|
[오픈 API] nodejs를 이용해 버스 도착 정보 얻기 - 1. API 사용법 (0) | 2019.02.15 |
프론트엔드 예제 블로그 만들기 (0) | 2019.01.05 |
[nodejs] 학식 카톡봇 예제 (0) | 2018.10.06 |
Node js로 유튜브 동영상 다운로드 받기 (0) | 2018.10.02 |