참고 자료 :
코드스테이츠,
드림코딩 엘리
node.js는 싱글 스레드 (단일 스레드)이다. 스레드는 실행의 단위이다. 한번에 처리할 수 있는 일의 개수가 1개라는 뜻이다.
node.js에서 자체적으로 제공하는 메소드에 Sync라는 단어가 붙어있으면 무조건 동기적으로 실행하는 메소드라는 뜻이다.
이 메소드는 세가지 인자를 갖는다.
첫번째 인자는 filePath
두번째 인자는 [option] : 유니코드를 의미한다. 있어도 되고 없어도 되지만, 없으면 영어만 인코딩 된다. 보통 한국어파일을 읽기 위해 "utf8"을 쓴다.
세번째 인자는 콜백 함수이다. 콜백함수의 인자로 err, file을 넘겨준다.
file : 우리가 원하는 문서 데이터가 들어온다.
err : 문서 데이터를 불러오지 못했을 때 err를 리턴한다.
조건문을 걸고 에러인 경우 콜백함수를 호출하고 그 인자로 err, null 순서로 준다.
에러가 아닌경우 else 문에서 콜백함수를 호출하고 null, file 순서로 준다.
콜백 방식으로도 비동기적인 모든것을 할 수 있다. 하지만 콜백 지옥은 매우 불편하다. 체계적으로 관리하기도 어려우며 가독성도 떨어진다. 비동기 작업들에 변수를 붙이고 싶기도 해서 프로미스가 나타났다. 프로미스는 then을 통해 resolve로 전달되는 결과를 받아와서 콜백 지옥 없이 비동기적으로 쓸수 있다. catch로 인해 err를 가지고 놀기도 편해졌다.
프로미스는 체이닝이라는 장점도 있고, 가장 중요한 부분은 프로미스올을 사용하여 비동기 작업을 한꺼번에 시키고 결과를 하나의 배열에 담을 수 있다.
const fs = require("fs");
const getDataFromFile = function (filePath, callback) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
callback(err, null) //에러를 출력할때 순서
} else {
callback(null, data) //에러가 아닐때 콜백 순서
}
})
};
getDataFromFile('README.md', (err, data) => console.log(data));
const path = require('path');
const { getDataFromFilePromise } = require('./02_promiseConstructor');
const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json');
// HINT: getDataFromFilePromise(user1Path) 맟 getDataFromFilePromise(user2Path) 를 이용해 작성합니다
const readAllUsersChaining = () => {
const user1 = getDataFromFilePromise(user1Path)
const user2 = getDataFromFilePromise(user2Path)
let result = []
return user1
.then(data1=> { //data1이 user1이 되는것
return user2
.then(data2=> { //data2가 user2가 되는것
data1 = JSON.parse(data1) //문자형태를 바꿔주기 위해 사용한다고 한다.
data2 = JSON.parse(data2)
result.push(data1)
result.push(data2)
return result
})
})
}
const path = require('path');
const { getDataFromFilePromise } = require('./02_promiseConstructor');
const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json');
const readAllUsers = () => {
const user1 = getDataFromFilePromise(user1Path).then(data1=>JSON.parse(data1))
const user2 = getDataFromFilePromise(user2Path).then(data2=>JSON.parse(data2))
let result = []
//중괄호가 있으려면 리턴이 있어야 하는데 리턴이 없기 때문에 중괄호를 쓰지 않아야 한다.
//그래서 8,9번째 제이슨을 써도 에러가 안나는 것이다.
return Promise.all([user1, user2])
//mdn에서 프로미스 문법을 검색해보면 된다. 프로미스 올에 대해 더 알아볼것
.then(([data1, data2])=>{ //구조분해할당
result.push(data1)
result.push(data2)
return result
})
}
readAllUsers()
const path = require('path');
const { getDataFromFilePromise } = require('./02_promiseConstructor');
const user1Path = path.join(__dirname, 'files/user1.json');
const user2Path = path.join(__dirname, 'files/user2.json');
const readAllUsersAsyncAwait = async () => {
const user1 = await getDataFromFilePromise(user1Path).then(data1=>JSON.parse(data1))
const user2 = await getDataFromFilePromise(user2Path).then(data2=>JSON.parse(data2))
let result = []
result.push(user1)
result.push(user2)
return result
}
자바스크립트의 내장 객체이다. 비동기적인 것을 수행할 때 콜백 함수 대신에 유용하게 쓸 수 있는 객체다.
콜백에서 한걸음 더 발전한 문법이다.
state : 프로세스가 무거운 오퍼를 수행하고 있는 중인지, 아니면 오퍼 수행을 다 하고 성공 했는지, 실패한 상태인지
프로듀서와 컨슈머의 차이점 알기 : 프로듀서는 우리가 원하는 데이터를 제공하는 사람이고 컨슈머는 제공된 데이터를 필요로 하는 사람이다. 둘의 다른 견해를 이해하자.
pending : 프로미스가 만들어 져서 우리가 지정한 오퍼가 수행 중일 때
fulfilled : 오퍼레이션을 성공적으로 끝내게 되었을 때
reject : 파일을 찾을 수 없거나 네트워크에 문제가 생기는 오류가 발생 했을 때
프로미스는 클래스이기 때문에 new 라는 키워드를 활용해 클래스로 생성할 수 있다.
프로미스에는 resolve(전달할 값)와 reject(오류)라는 두가지 인자가 필요하다.
const 변수 = filePath => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
}
)
};
1. Basic Chainig
var newsURL = 'http://localhost:5000/data/latestNews';
var weatherURL = 'http://localhost:5000/data/weather';
function getNewsAndWeather() {
let obj = {}
return new Promise ((resolve, reject) => {
fetch(newsURL)
.then((response) => response.json())
.then((json) => {
obj.news = json.data
return fetch(weatherURL)
.then((response) => response.json())
.then((json) => {
obj.weather = json
resolve(obj)
})
} )
})
}
2. promiseAll
var newsURL = 'http://localhost:5000/data/latestNews';
var weatherURL = 'http://localhost:5000/data/weather';
function getNewsAndWeatherAll() {
// TODO: Promise.all을 이용해 작성합니다
const news = fetch(newsURL).then(response => response.json())
const weather = fetch(weatherURL).then(response => response.json())
let result = {};
return Promise.all([news, weather])
.then(([data1, data2]) => { //구조분해할당 문법
result.news = data1.data
result.weather = data2
return result;
})
}
//프로미스올은 구조분해할당 문법으로 2개를 한꺼번에 묶어서 제이슨화 시킨 후
//서버에서 받은 정보를 새로운 객체에 각각 넣어주었다.
3. asyncawait
var newsURL = 'http://localhost:5000/data/latestNews';
var weatherURL = 'http://localhost:5000/data/weather';
async function getNewsAndWeatherAsync() {
const news = await fetch(newsURL).then(response => response.json())
const weather = await fetch(weatherURL).then(response => response.json())
let result = {};
result.news = news.data
result.weather = weather
return result
}
//어웨이트 코드가 제일 깔금하다. 문법의 발전의 결과물. 처음에 콜백 지옥 때문에 불편해서
//.덴이 나오고 덴이 불편하니 프로미스올이 나오고 그다음 어웨이트가 나왔다.
//어웨이트로 안되는것도 있기 때문에 그때는 프로미스올이나 덴을 사용한다.
Then, catch, finally
.then : 프로미스라는 변수를 만들고 값이 정상적으로 수행이 된다면, then 으로 값을 받아올 수 있다. 우리가 원하는 기능을 수행하는 콜백함수를 전달해주면 된다. then의 velue는 resolve에 들어온 값이다.
.catch : 덴의 끝에서 오류를 잡아 주는 기능을 한다. 다른 걸로 대체를 시켜서 프로미스 체이닝을 완성 되게 할수도 있다.
.finally : 최근에 추가되었다. 프로미스 체이닝이 성공하든, 실패하든 무조건 마지막에 호출되어진다.
파일의 텍스트가 문자열이기 때문에 제이슨 값으로 바꿔주기 위해서 쓴다.
1. JSON.parse : node.js에서 지원해주는 객체
2. JSON response : fetch에서 지원하는 메소드
두가지 모두 제이슨이 리턴되는것은 같지만 위치하는 곳이 다르다.