1. 자바스크립트 첫걸음
1) JavaScript가 뭔가요?
2) JavaScript에 발 담그기
3) 뭐가 잘못됐을까요? JavaScript 문제 해결
4) 필요한 정보 저장하기 — 변수
변수의 이름에 대한 규칙
- 변수 이름의 시작부분에 밑줄을 사용하지 마세요. 특별한 의미를 이미 가지고 있습니다.
- 숫자로 시작하지 마세요.
- lower camel case 를 쓰세요.
- 변수는 대소문자를 구분합니다.
- 예약어를 변수이름으로 사용하지 마세요.
예약어: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords
변수의 종류
- 숫자
- 문자열: 작은따옴표나 큰따옴표로 묶는다.
- 불리언 ex) var test = 6 < 3
- 배열
- 객체
지정되지 않은 타입
JavaScript 는 느슨한 유형의 언어 (loosely typed language) 입니다.
7) 유용한 문자열 메서드
string.
- length: 길이
- [index]: 문자
- indexOf()
- slice(0, 3)
- toLowerCase() / toUpperCase()
- replace()
8) 배열
2. JavaScript 구성 요소
3. JavaScript 객체 소개
4. 비동기적 JavaScript
1) Introducing asynchronous JavaScript
JavaScript 에서 볼 수 있는 비동기 스타일은 두 가지 유형이 있습니다.
예전 방식인 callbacks 그리고 새로운 방식인 promise-stype 코드입니다.
Promises
Promises 모던 Web Apis 에서 보게 될 새로운 코드 스타일입니다.
좋은 예는 fetch() API 입니다.
fetch() 는 CMLHttpRequest 보다 좀 더 현대적인 버전 입니다.
예제: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data
fetch('products.json').then(function(response) {
return response.json();
}).then(function(json) {
products = json;
initialize();
}).catch(function(err) {
console.log('Fetch problem: ' + err.message);
});
fetch() 는 단일 매개변수만 전달받습니다.
promise 는 비동기 작업이 성공했는지 혹은 실패했는지를 나타내는 하나의 오브젝트 입니다.
즉 성공/실패의 분기점이 되는 중간의 상태라고 표현할 수 있습니다.
왜 promise 라는 이름이 붙었는지 잠깐 살펴보자면.. "내가 할 수 있는 한 빨리 너의 요청의 응답을 가지고 돌아간다고 약속 (promise) 할게"
라는 브라우저의 표현방식이어서 그렇습니다.
- 두 개의 then() 블럭: 두 함수 모두 이전 작업이 성공했을때 수행할 작업을 나타내는 callback 함수 입니다. 그리고 각 callback함수는 인수로 이전 작업의 성공 결과를 전달받습니다. 따라서 성공했을때의 코드를 callback 함수 안에 작성하면 됩니다. 각 .then() 블럭은 서로 다른 promise를 반환합니다. 이 말은 .then() 을 여러개 사용하여 연쇄적으로 작업을 수행하게 할 수 있음을 말합니다. 따라서 여러 비동기 작업을 차례대로 수행할 수 있습니다.
- catch() 블럭은 .then() 이 하나라도 실패하면 동작합니다. — 이는 동기 방식의 try...catch 블럭과 유사합니다. error 오브젝트는 catch()블럭 안에서 사용할 수 있으며, 발생한 오류를 보고하는 용도로 사용할 수 있습니다. 그러나 try...catch 는 나중에 배울 async/await에서는 동작하지만, promise와 함께 동작할 수 없음을 알아두세요.
2) How to use promises
우리가 Promise 로 가장 많이 할 작업 중 하나는 Promise 를 반환하는 웹 API 를 사용하는 것 입니다.
Promise terminology recap
- Promise 가 생성되면 그 상태는 성공도 실패도 아닌 pending 상태라고 부릅니다.
- Promise 결과가 반환되면 결과와 상관 없이 resolved 상태라고 부릅니다.
- 성공적으로 처리된 Promise 는 fulfilled 상태이다. 이 상태가 되면 Promise 체인의 다음 .then() 블럭에서 사용할 수 있는 값을 반환한다. 그리고 .then() 블럭 내부의 executor 함수에 Promise 에서 반환된 값이 파라미터로 전달된다.
- 실패한 Promise 는 rejected 상태이다.
Running code in response to multiple promises fulfilling
위의 예제에서 Promise사용의 기초를 확인했습니다. 이제 고급 기능들을 한번 보겠습니다. 제일 먼저 확인해볼 예제는 다음과 같습니다. 연쇄적으로 일어나는 작업은 좋습니다. 그런데 모든 Promise가 fulfilled일 경우 코드를 실행하고 싶은 경우가 있을것 입니다.
해당 기능을 Promise.all() 이라는 스테틱 메서드를 사용하여 만들 수 있습니다. 이 메서드는 Promise의 배열을 매개변수로 삼고, 배열의 모든 Promise가 fulfil일 때만 새로운 fulfil Promise 오브젝트를 반환합니다. 아래처럼 말이죠 :
Promise.all([a, b, c]).then(values => {
...
});
Running some final code after a promise fulfills/rejects
Promise의 결과가 fulfilled 인지 rejected인지 관계 없이 Promise가 완료된 후 최종 코드 블럭을 실행하려는 경우가 있을 것입니다. 이전에는 아래 예시처럼 .then() 블럭과.catch() 블럭의 callbacks에 아래와 같이 runFinalCode()를 넣었었습니다. :
보다 최근의 현대 브라우저에서는 .finally() 메서드를 사용할 수 있습니다. 이 메서드를 Promise 체이닝의 끝에 배치하여 코드 반복을 줄이고 좀 더 우아하게 일을 처리할 수 있습니다. 아래와 같이 마지막 블럭에 적용할 수 있습니다. :
myPromise
.then(response => {
doSomething(response);
})
.catch(e => {
returnError(e);
})
.finally(() => {
runFinalCode();
});
Building your own custom promises
Using the Promise() constructor
Promise() constructor를 사용하여 사용자 정의 Promise를 만들 수 있습니다. 주로 Promise기반이 아닌 구식 비동기 API코드를 Promise기반 코드로 만들고 싶을 경우 사용합니다. 이 방법은 구식 프로젝트 코드, 라이브러리, 혹은 프레임워크를 지금의 Promise 코드와 함께 사용할 때 유용합니다.
Rejecting a custom promise
reject() 메서드를 사용하여 Promise가 reject상태일 때 전달할 값을 지정할 수 있습니다. — resolve()와 똑같습니다. 여기엔 하나의 값만 들어갈 수 있습니다. Promise가 reject 되면 에러는 .catch() 블럭으로 전달됩니다.
이전 예시를 좀 더 확장하여 reject() 을 추가하고, Promise가 fulfil일 때 다른 메시지도 전달할 수 있게 만들어봅시다.
A more real-world example
비동기 및 대기
이 async 키워드는 비동기 약속 기반 코드로 작업하는 더 간단한 방법을 제공합니다.
함수 시작 부분에 추가 async 하면 비동기 함수가 됩니다.
async function myFunction() {
// This is an async function
}
await비동기 함수 내 에서 약속을 반환하는 함수를 호출하기 전에 키워드를 사용할 수 있습니다 . 이렇게 하면 코드가 약속이 해결될 때까지 해당 지점에서 기다리게 됩니다. 이때 약속의 이행된 값은 반환 값으로 처리되거나 거부된 값이 throw됩니다.
이를 통해 비동기 함수를 사용하지만 동기 코드처럼 보이는 코드를 작성할 수 있습니다. 예를 들어, 가져오기 예제를 다시 작성하는 데 사용할 수 있습니다.
async function fetchProducts() {
try {
const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
return data;
}
catch(error) {
console.error(`Could not get products: ${error}`);
}
}
const promise = fetchProducts();
console.log(promise[0].name); // "promise" is a Promise object, so this will not work
대신에 다음과 같이 작성해야 합니다.
async function fetchProducts() {
try {
const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json();
return data;
}
catch(error) {
console.error(`Could not get products: ${error}`);
}
}
const promise = fetchProducts();
promise.then((data) => console.log(data[0].name));
async 함수 바깥에서 await 를 사용하는 것은 모듈 내에서만 허용된다.
결론
Promise는 현대 JavaScript에서 비동기 프로그래밍의 기초입니다. 깊이 중첩된 콜백 없이 비동기 작업 시퀀스에 대해 더 쉽게 표현하고 추론할 수 있으며 동기 try...catch문과 유사한 오류 처리 스타일을 지원합니다.
키워드 await 및 async를 사용하면 일련의 연속 비동기 함수 호출에서 작업을 더 쉽게 빌드할 수 있으므로 명시적 약속 체인을 만들 필요가 없고 동기 코드처럼 보이는 코드를 작성할 수 있습니다.
3) Implementing a promise-based API
alarm() API 구현하기
이 예제에서는 alarm()이라는 프로미스 기반 알람 API를 구현할것입니다. 깨울 사람의 이름과 깨울 때까지 기다리는 지연 시간(밀리초)이 인수로 사용됩니다. 기다림이 끝나면 함수는 깨워야 할 사람의 이름과 "Wake up!" 이라는 문구를 메시지로 보냅니다.
Promise() 생성자
alarm() 함수는 타이머가 만료되었을 때 이행되는 Promise를 반환합니다. 그러면 "Wake up!" 메시지를 then() 처리기로 전달하며, 발신자가 음의 지연 값을 제공할 경우 프로미스를 거부합니다.
여기서 핵심 구성 요소는 Promise() 생성자입니다. Promise() 생성자는 하나의 함수를 인수로 사용합니다. 우리는 이 기능을 executor(실행자)라고 부릅니다. 새 프로미스를 만들 때 실행자의 구현을 제공합니다.
이 실행자 함수 자체에는 두 개의 인수가 필요한데, 이 인수는 함수이기도 하고, 관습적으로 resolve와 reject라고 불립니다. 실행자 구현에서는 기본 비동기 함수를 호출합니다. 비동기 함수가 성공하면 resolve를 호출하고 실패하면 reject를 호출합니다. 실행자 함수가 오류를 발생시키면 reject가 자동으로 호출됩니다. 모든 유형의 단일 매개 변수를 resolve 및 reject로 전달할 수 있습니다.
function alarm(person, delay) {
return new Promise((resolve, reject) => {
if (delay < 0) {
throw new Error('Alarm delay must not be negative');
}
window.setTimeout(() => {
resolve(`Wake up, ${person}!`);
}, delay);
});
}
alarm() 을 async 와 await 와 함께 사용하기
alarm()은 Promise를 반환하기 때문에 promise.all()과 async / await, 프로미스 체이닝 등 프로미스로 할 수 있는 모든 것을 할 수 있습니다.
const name = document.querySelector('#name');
const delay = document.querySelector('#delay');
const button = document.querySelector('#set-alarm');
const output = document.querySelector('#output');
function alarm(person, delay) {
return new Promise((resolve, reject) => {
if (delay < 0) {
throw new Error('Alarm delay must not be negative');
}
window.setTimeout(() => {
resolve(`Wake up, ${person}!`);
}, delay);
});
}
button.addEventListener('click', async () => {
try {
const message = await alarm(name.value, delay.value);
output.textContent = message;
}
catch (error) {
output.textContent = `Couldn't set alarm: ${error}`;
}
});
Promise 를 반환한다면 async 함수에 await 를 사용하면 된다.
4) Introducing workers (en-US)
이 과정의 첫 번째 글에서 우리는 프로그램이 장기간 진행되는 동기 작업을 수행할 때 창이 완전히 응답하지 않는 것을 보았습니다. 근본적으로 그 이유는 프로그램이 단일 스레드 이기 때문입니다. 스레드 는 프로그램이 따르는 일련의 명령입니다. 이 프로그램이 단일 스레드로 구성되어 있어서 한 번에 한 가지 작업만 수행할 수 있습니다. 따라서 장기간 실행 중인 동기 호출이 반환되기를 기다리고 있으면 다른 작업을 수행할 수 없습니다.
웹에서는 이러한 문제를 방지하기 위해 메인 코드와 워커 코드가 서로의 변수에 직접 접근할 수 없습니다. 워커와 메인 코드는 완전히 별개의 세계에서 실행되며, 서로 메시지를 보내야만 상호 작용할 수 있습니다. 특히, 워커는 DOM(window, document, 페이지 요소 등)에 액세스할 수 없습니다.
워커에는 세 가지 유형이 있습니다.
- dedicated workers
- shared workers
- 서로 다른 창에서 실행되는 여러 스크립트에서 공유될 수 있습니다.
- service workers
- 사용자가 오프라인 상태일 때 웹 어플리케이션이 작동할 수 있도록 리소스를 캐싱하는, 마치 프록시 서버처럼 작동합니다.
5. Client-side web APIs
6. JavaScript on MDN
7. JavaScript 배우기
8. EXLskills의 JavaScript 기초
'Others > 시작하기' 카테고리의 다른 글
Go 프로젝트 디렉토리 구조 잡기 (0) | 2023.04.30 |
---|---|
Create go app 시작하기 (0) | 2023.04.28 |
리눅스 시작하기 (0) | 2022.08.22 |
Learn IDE Features for Go (GoLand) (0) | 2022.06.26 |
Go Gopher 길들이기 (0) | 2022.06.23 |