Chapter1. 고차함수 리뷰
Chapter2. 비동기
2-1. 비동기 호출
2-2. 비동기 JavaScript
2-3. Callback
2-4. Promise, async/await
2-5. 타이머 API
Chapter3. Node.js
3-1. Node.js 모듈 사용법
3-2. Node.js 공식 문서 가이드
Chapter4. fetch API
4-1. fetch를 이용한 네트워크 요청
resolve
와 reject
를 활용할 수 있다.new Promise()
를 통해 생성한 Promise 인스턴스가 사용할 수 있는 메서드의 용도를 이해한다.async
/await
키워드와 함께 실행되는 함수는 어떤 타입이어야 하는지 이해한다.await
키워드를 사용할 경우 어떤 값이 리턴되는지 설명할 수 있다.커피숍 사정상, 커피를 주문한 먼저 온 김코딩이 주문한 커피를 받을 때까지, 줄 서 있는 박해커가 주문조차 할 수 없다고 하겠습니다. 이를 우리는 blocking 이라고 부릅니다. 하나의 작업이 끝날 때까지, 이어지는 작업을 "막는 것"입니다.
박해커는 김코딩이 주문한 커피가 나오고 나서야 커피를 주문할 수 있습니다. 김코딩의 커피 주문 완료 시점과 박해커의 커피 주문 시작 시점이 같습니다. 이렇게 시작 시점과 완료 시점이 같은 상황을 "동기적(synchronous)이다." 라고 합니다.
Node.js를 만든 개발자는 Node.js를 non-blocking하고 비동기적(asynchronous)으로 작동하는 런타임으로 개발하게 됩니다
JavaScript의 비동기적 실행(Asynchronous execution)이라는 개념은 웹 개발에서 특히 유용합니다. 특히 아래 작업은 비동기적으로 작동되어야 효율적입니다.
function waitSync(ms) {
var start = Date.now();
var now = start;
while(now - start < ms) {
now = Date.now();
}
} // 현재 시각과 시작 시각을 비교하며 ms 범위 내에서 무한 루프를 도는 blocking 함수입니다
function drink(person, coffee) {
console.log(person + '는 ' + coffee + '를 마십니다');
}
function orderCoffeeSync(coffee) {
console.log(coffee + '가 접수되었습니다');
waitSync(2000);
return coffee;
}
let customers = [{
name: 'Steve',
request: '카페라떼'
}, {
name: 'John',
request: '아메리카노'
}];
// call synchronously
customers.forEach(function(customer) {
let coffee = orderCoffeeSync(customer.request);
drink(customer.name, coffee);
});
function waitAsync(callback, ms) {
setTimeout(callback, ms); // 특정 시간 이후에 callback함수가 실행되게끔하는 브라우저 내장 기능입니다
}
function drink(person, coffee) {
console.log(person + '는 ' + coffee + '를 마십니다');
}
function orderCoffeeAsync(menu, callback) {
console.log(menu + '가 접수되었습니다');
waitAsync(function() {
callback(menu);
}, 4000);
}
let customers = [{
name: 'Steve',
request: '카페라떼'
}, {
name: 'John',
request: '아메리카노'
}];
//call asynchoronously
customers.forEach(function(customer) {
orderCoffeeAsync(customer.request, function(coffee) {
drink(customer.name, coffee);
});
});
function orderCoffeeSync(coffee) {
console.log(coffee + '가 접수되었습니다');
waitSync(2000);
return coffee;
}
function orderCoffeeAsync(menu, callback) {
console.log(menu + '가 접수되었습니다');
waitAsync(function() {
callback(menu);
}, 4000);
}
1.callback 패턴
let request = 'latte';
odrAsync(request, function(res) {
// res ->주문한 커피 결과
drink(res);
};
2.이벤트 등록 패턴
let request = 'latte';
odrAsync(request).onready = function(res) {
// res ->주문한 커피 결과
drink(res);
};
브라우저의 비동기 함수 작동 원리를 알려면 => event Loop 검색
JavaScript는 엔진은 Single Thread(한번에 하나의 작업만 수행함)이다.
그래서 동시에 두 가지 작업을 할 수 없다.
그렇다면 여러 작업이 동시에 요청이 될 때 이 전 작업이 마무리 될 때까지 기다려야 하는가? 그렇다.
그래서 JavaScript 엔진은 비동기 처리가 가능하도록 설계되었다.
-> 콜백함수
, promise
, async&await
A callback function is a function passed into another function as an argument[MDN]
- 자바스크립트의 메인스레드인 이벤트 루프가 싱글스레드 여서 자바스크립트를 싱글스레드 언어라고 부른다. 그러나 자바스크립트는 이벤트 루프만 독립적으로 실행하지 않고, 웹 브라우저나 NodeJS 같은 멀티쓰레드 환경에서도 실행됨.
- 즉 비동기, 논블록킹 작업들은 JS엔진을 구동하는 웹 브라우저와 NOdeJS에서 담당한다.
자스동작원리
1.익명함수 사용
Promise
, async
/await
를 사용해 방지할 수 있음new Promise()
를 통해서 하나의 promise 인스턴스 객체가 만들어짐비동기 작업이 성공적으로 이행되면 resolve()를 호출하고,
오류가 발생해 작업 실패시 reject()를 호출한다.
const promise1 = new Promise(function (resolve, reject) {
/*비동기작업*/
resolve() // -> go to next action
reject() // -> handle error
})
Executor
가 들어가는 데 Executor
는 resolve와 reject라는 두 개의 함수를 매개변수로 받는 실행함수이다. resolve와 reject를 호출하는 애가 얘임then
메소드와 catch
메소드에 의해 실행된다. 둘 다 인자로 함수를 받고, Promise를 반환한다.const promise1 = new Promise( (resolve, reject)=> {
/*비동기작업*/
})
promise1
.then(() => {
console.log("then!")
//resolve가 호출되면 then이 실행됨
})
.catch(() => {
console.log("catch!")
//reject가 호출되면 catch가 실행됨
})
.finally(
//콜백 작업을 마치고 무조건 실행되는 finally(생략가능)
)
예제
const yes = true;
const promise2 = new Promise((resolve, reject) => {
if(yes) {
resolve('비동기 작업 성공시 리턴메시지')
} else {
reject('비동기 작업 실패,에러시 리턴')
}
})
pppromise2
.then((res)=>{
console.log(res)
})
.catch((err) =>{
console.log(err)
})
// 결과 : 비동기 작업 성공시 리턴메시지
예제
const promise = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(4);
}, 1000);
});
promise
.then((res) => {
console.log(res + 'complete'); //4complete
return res + 1; /// return = 5
}).catch(() => {
console.log('앞 체인이 fulfilled라면 catch는 무시된다.')
}).then((value) => {
console.log(value) // 5
});
프로미스의 상태란 프로미스의 처리과정을 의미한다.
new Promise()로 프로미스를 생성하고 작업이 종료될 때까지 3가지 상태를 갖는다.
Promise 메서드 안쪽 콜백의 실행결과에 따라 Promise는 둥 중 하나의 상태로 귀결됨.
fulfilled: 비동기 처리가 성공적으로 진행되었다는 뜻이다.
rejected: 비동기 처리가 실패했다는 뜻이다.
Promise 메서드의 콜백에서 Promise가 아닌 값을 리턴한다면 (또는 아무것도 리턴하지 않아 undefined를 리턴한 셈이 되었다면), fulfilled 된 것으로 취급한다.
fulfilled 처리된 체인 다음에 오는 체인들 중 제일 처음으로 등장하는 then이 그것을 받아들이며, 리턴되었던 값을 인자로 받는다.
Promise 메서드의 콜백에서 에러가 난다면 rejected
된 것으로 처리한다.
rejected
처리된 체인 다음에 오는 체인들 중 제일 처음으로 등장하는 catch가 그것을 받아들이며, 발생한 에러를 인자로 받는다.Promise 이전의 비동기 처리는 Callback함수를 설정하는 방식으로 이루어졌다. 비동기가 완료되는 시점에 실행이 되는 callback함수로 완료를 인지하고 그 다음을 처리한 것이다. 그렇게 하다보니 비동기 처리를 연속적으로 해야하는 경우 Callback함수에 Callback함수가 들어가고 거기에 또 Callback함수가 들어가는 이상하고 요상한 코드가 되어 버렸다. 이것을 이른바 Callback Hell 이라고 한다.
//콜백헬
const printString = (string, callback) => {
setTimeout(() => {
console.log(string)
callback()
}, Math.floor(Math.random() * 100) + 1);
}
const printAll = () => {
printString ("A", () => {
printString ("B", () => {
printString ("C", () => {})
})
})
}
printAll() // ABC
Promise를 이용하여 이러한 Callback Hell을 말끔히 탈출할 수 있는 것은 아니지만 Callback을 함수로 바로 넘겨받지 않고 객체에 이어서 사용할 수 있게 되면서 훨씬 보기 쉬워졌다.
//프로미스를 활용
const printString = (string) => {
return new Promise ((resolve, reject) => {
setTimeout(() => {
console.log(string)
resolve()
}, Math.floor(Math.random() * 100) + 1);
})
}
const printAll = () => {
printString ("A")
.then(() => {
return printString("B")
})
.then(() => {
return printString("C")
})
}
printAll()
promise는 비동기 처리에 있어서 객체의 개념을 도입했다는 점이 가장 큰 특징이다. 그래서 자바스크립트에서 객체가 사용할 수 있는 메소드를 활용할 수있다고 한다.
Promise.all(iterable);
동시에 두 개 이상의 Promise 요청을 한꺼번에 실행하는 함수
매개변수 iterable
Array와 같이 순회 가능한(iterable) 객체
resolve
를 호출하며, 하나라도 비동기 작업시 실패하면 reject
를 호출Promise.all
배열 내 모든 값의 이행(또는 첫 번째 거부)을 기다립니다.async/await는 Promise로 된 비동기 코드를 동기적으로 쓸수 있게 해주는 문법이다.
const getData1 = () => {
const promise = fetch('htttps://example.com/api')
.then(res => {
return res.json()
}).then(data => {
console.log(data)
});
return promise
}
이런 코드는
const getData2 = async () => {
const res = await fetch('htttps://example.com/api')
const data = await res.json();
console.log(data);
return data;
}
async/await로 이렇게 고칠 수 있다.
함수 앞에 async 키워드를 붙이고, promise 값 앞에 await 키워드를 붙이기만 하면 promise 메서드 없이 값을 사용할 수 있게 된다.
비동기코드같지 않고 동기적 코드같다.
async function 함수명(){
await 비동기_처리_메서드_명();
}
.then
메소드를 사용할 수 있다.예제
function 딜레이(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function 사과() {
await 딜레이(7000)
return '🍎'
}
async function 바나나() {
await 딜레이(2000)
return '🍌'
}
async function 클로바(){
await 딜레이(5000)
return '☘️'
}
사과().then(console.log) //7초후 리턴
바나나().then(console.log) //2초후 리턴
클로바().then(console.log) //5초후 리턴
//결과 🍌☘️🍎
try
.. catch
.. 구문으로 예외처리
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(()=> {
return resolve('성공')
}, 2000)
})
}
async function loadData() {
try{
const res = await fetchData()
console.log(res)
} catch(e) {
console.log(e)
}
}
loadData() //
비동기적 방식 처리방법
async function
[Node.js] 비동기 / Promise 동작원리 / SPRINT-비동기 💯️
JavaScript 비동기 처리를 위한 promise 이해하기 프라미스올!!!
[Javascript] 비동기, Promise, async, await 확실하게 이해하기
promise 잘사용하기
바보들을 위한 PROMISE
일정 시간 후에 함수를 실행
setTimeout( function() {
console.log('1초 후 실행');
}, 1000);
setTimeout 함수는 비동기 함수이다.
setTimeout 타이머를 종료
const timer = setTimeout(function(){
console.log('10초 후 실행');
}, 10000);
clearTimeout(timer); //setTimeout이 종료됨
일정 시간의 간격을 가지고 함수를 반복적으로 실행
setInterval(function () {
console.log('2초마다 실행');
}, 2000);
// 345
setInterval 타이머를 종료
const timer = setInterval(function () {
console.log('1초마다 실행');
}, 1000);
clearInterval(timer); // setInterval이 종료됨.
fs.readFile
을 이용할 수 있다.Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
- 크롬 V8엔진을 기반으로 한 자바스크립트 런타임(실행환경)
- 자바스크립트로 웹 서버를 만들 수 있는 툴
Non-blocking I/O
-> 덕분에 채팅/SNS에 자주 사용
브라우저에서 사용할 수 있는 비동기 흐름은 한정적이지만, Node.js의 경우 많은 API가 비동기로 작성되어 있음
Node.js 모듈 사용하는 방법 익힌 뒤, 이를 가지고 비동기 상황을 연출하고 연습 하자
모듈?
건축으로부터 비롯된 모듈이라는 단어는, 어떤 기능을 조립할 수 있는 형태로 만든 부분입니다.
ex)fs(File System)
모듈은, PC의 파일을 읽거나 저장하는 등의 일을 할 수 있게 도와줍니다.
개발자는 자신이 이해하는 범위만큼 모듈을 사용할 수 있음
모듈을 사용한다 ?
ex) DNS에 대한 지식을 알고 있다면, DNS 모듈 사용법 문서에서 관련 필요한 메서드를 찾아 사용할 수 있는 것
fs(file system) 모듈
readFile
메서드writeFile
메서드모든 모듈은 '모듈을 사용하기 위해 불러오는 과정'이 필요
Node.js 에서는 JavaScript 코드 가장 상단에 require
구문을 이용하여 다른 파일을 불러옵니다.
const fs = require('fs'); // 파일 시스템 모듈을 불러옵니다
const dns = require('dns'); // DNS 모듈을 불러옵니다
// 이제 fs.readFile 메서드 등을 사용할 수 있습니다!
서드 파티 모듈(3rd-party module)은 해당 프로그래밍 언어에서 공식적으로 제공하는 빌트인 모듈(built-in module)이 아닌 모든 외부 모듈을 일컫습니다.
underscore
는 Node.js 공식 문서에 없는 모듈이기 때문에 서드 파티 모듈입니다. underscore
와 같은 서드 파티 모듈을 다운로드하기 위해서는 npm을 사용해야 합니다.require
구문을 통해 underscore 를 사용가능npm install underscore
const _ = require('underscore');
메서드 fs.readFile
은 로컬에 존재하는 파일을 읽어옵니다.
메서드 fs.readFile
은 비동기적으로 파일 내용 전체를 읽습니다. 이 메서드를 실행할 때에는 전달인자 세 개를 받습니다.
path
string || Buffer || URL || integerpath에
는 파일 이름을 전달인자로 받습니다. 네 가지 종류의 타입을 넘길 수 있지만 일반적으로 문자열(<string>
)의 타입을 받습니다.
options
Object || string대괄호로 감싼 두 번째 전달인자 options는 넣을 수도 있고, 넣지 않을 수도 있습니다. 대괄호는 선택적 전달인자를 의미합니다.
options는 문자열 또는 객체 형태로 받을 수 있습니다. 문자열로 전달할 경우 인코딩을 받습니다.
// 문자열
// /etc/passwd 파일을 'utf8'을 사용하여 읽습니다.
fs.readFile('/etc/passwd', 'utf8', ...);
// 객체
let options = {
encoding: 'utf8', // utf8 인코딩 방식으로 엽니다
flag: 'r' // 읽기 위해 엽니다
}
// /etc/passwd 파일을 options를 사용하여 읽습니다.
fs.readFile('/etc/passwd', options, ...)
callback
Function콜백 함수를 전달합니다. 파일을 읽고 난 후에 비동기적으로 실행되는 함수입니다.
err
Error||AggregateError
data
string || Buffer
콜백 함수에는 두 가지 매개변수가 존재합니다. 에러가 발생하지 않으면 err
는 null
이 되며, data
에 문자열이나 Buffer
라는 객체가 전달됩니다.
data
는 파일의 내용입니다.
fs.readFile('test.txt', 'utf8', (err, data) => {
if (err) {
throw err; // 에러를 던집니다.
}
console.log(data);
});
비동기 요청의 가장 대표적인 사례는 단연 네트워크 요청입니다. URL로 요청하는 경우가 가장 흔하고 이를 가능하게 해 주는 API가 바로 fetch API입니다.
포털사이트는 시시각각 변하는 정보와, 늘 고정적인 정보가 따로 분리되어 있는 것을 확인할 수 있습니다. 이 중에서 최신 뉴스나 날씨/미세먼지 정보가 바로 동적으로 데이터를 받아야 하는 정보입니다.
이럴 때 많은 웹사이트에서는 해당 정보만 업데이트하기 위해 요청 API를 이용합니다. 그중 대표적인 fetch API를 이용해 해당 정보를 원격 URL로부터 불러오는 경우를 설명합니다.
원격 URL로부터 정보를 받아와서 특정 DOM 엘리먼트를 업데이트하는 경우
//URL 예시
http://기상청.com/data/currentWeather.json
http://기상청.com/data/currentFinedust.json
http://뉴스포털.com/data/latestNews.json
fetch API는 특정 URL로부터 정보를 받아오는 역할을 합니다. 이 과정이 비동기로 이루어지기 때문에, 경우에 따라 다소 시간이 걸릴 수 있습니다.
개발자 도구의 콘솔에서 fetch API를 사용하여 데이터를 요청할 수 있음
let url ="https://v1.nocodeapi.com/codestates/google_sheets/YbFMAAgOPgIwEXUU?tabId=최신뉴스";
fetch(url)
.then((response) => response.json())
.then((json) => console.log(json))
.catch((error) => console.log(error));
에러 발생
이유: API rate limits exceeded. Please upgrade your account.
fetch API는 특정 URL로 부터 데이터를 받아오는 역할을 한다.
Node.js 환경을 떠나, 브라우저에서 진행함
Node.js 환경에는 fetch API가 내장 모듈로 제공되지 않습니다.
fetch를 이용해 HTTP 요청을 보내고, 응답을 받는 연습을 합니다.