JavaScript는 싱글 스레드 기반의 언어로, 한 번에 하나의 작업만 처리할 수 있습니다. 왜냐하면 코드를 읽고 실행하는 'stack'이 하나만 존재하기 때문이죠.
동기 작업은 순차적으로 실행되며, 이전 작업이 완료되어야 다음 작업이 실행됩니다. 한 작업이 실행 중인 동안 다른 작업들은 대기 상태에 있습니다. 작업의 결과를 기다리는 동안 프로그램이 블로킹되는 특징이 있습니다. 예를 들어, 함수 호출이 동기적으로 처리되면 해당 함수의 반환 값을 받을 때까지 다음 코드 실행이 차단됩니다.
비동기 작업은 작업이 백그라운드에서 실행되며, 작업이 완료되기를 기다리지 않고 다음 코드가 즉시 실행됩니다. 비동기 작업은 별도의 스레드나 백그라운드에서 처리되므로, 작업의 결과를 기다리는 동안 프로그램이 블로킹되지 않습니다. 비동기 작업은 일반적으로 콜백 함수, Promise, async/await와 같은 메커니즘을 사용하여 작업이 완료되면 결과를 처리하거나 다음 작업을 정의합니다.
비동기 작업은 주로 시간이 오래 걸리는 작업(예: 네트워크 요청, 파일 I/O, 데이터베이스 쿼리 등)이나 이벤트 기반 작업(예: 사용자 입력, 타이머, 애니메이션 등)에 사용됩니다. 비동기 작업을 사용하면 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있으므로, 애플리케이션의 반응성과 성능을 향상시킬 수 있습니다.
따라서 JavaScript는 기본적으로는 동기적으로 동작하는 언어이지만, 다양한 method(setTimeout, event listener, ajax 함수 등)를 사용해서 비동기적인 작업이 가능하도록 해줘 작업 속도와 효율성을 높이고 있습니다. 이러한 비동기 작업을 쉽고 간결하게 관리할 있도록 도와주는 기술에는 Promise와 Async/Await가 있습니다.
Promise는 비동기 작업을 처리하는 패턴 중 하나로 콜백 지옥(callback hell)을 피할 수 있도록 해주고, 작업들을 연결하고 조합하는 방법을 제공합니다. 비동기 작업이 성공적으로 완료되었는지 또는 실패했는지를 나타내는 상태와 결과값을 제공해주죠. Promise는 비동기 작업을 체인으로 연결하여 순차적으로 처리할 수 있고, 에러 처리도 간편하게 할 수 있습니다.
이 덕분에 코드 흐름을 파악하기 쉽고, 비동기 작업의 성능 향상이라는 장점은 그대로 유지한 채, 개발자가 동기적으로 비동기 작업의 움직임을 예측하고 처리할 수 있도록 도와줍니다.
async/await는 Promise를 더 쉽게 사용할 수 있도록 만든 JavaScript의 문법적인 개선입니다. async 함수는 비동기 작업을 수행하고 Promise를 반환하는 함수입니다. await 키워드는 async 함수 내에서 사용되며, 비동기 작업의 결과를 기다리는 역할을 합니다. await 키워드를 사용하면 코드를 동기적으로 작성할 수 있으며, 작업이 완료될 때까지 다음 코드의 실행을 일시 중지합니다. 이를 통해 비동기 작업을 동기적으로 표현하고, 비동기 코드의 가독성을 향상시킵니다. 에러 처리도 try-catch 문으로 간편하게 처리할 수 있습니다.
Promise와 async/await를 사용하면 비동기 작업의 흐름을 명확하게 표현할 수 있고, 작업들 간의 의존성과 순서를 조작하기 쉽습니다. 또한, 에러 처리도 보다 간단하고 효율적으로 할 수 있습니다. 이러한 기술들은 코드의 가독성과 유지보수성을 높이며, 비동기 작업을 보다 직관적이고 효율적으로 처리할 수 있도록 도와줍니다.
그런데 자바스크립트는 단일 스레드 기반 언어로, 한번에 하나의 작업만 처리할 수 있다고 했습니다. 그런데 어떻게 여러 작업들이 동시에 진행될 수 있는걸까요? 이는 '이벤트 루프' 덕분에 가능합니다.
'setTimeout, XMLHttpRequset, 이벤트 처리'와 같은 비동기 작업이 발생하면, 이벤트 루프는 해당 작업을 백그라운드로 보내고 콜백 함수를 등록합니다. 이때 응답된 콜백 함수는 이벤트 큐로 이동됩니다. 호출 스택이 비어 있는 상태에서 이벤트 큐에 콜백 함수가 있는 경우, 이벤트 루프는 콜백 함수를 호출 스택으로 이동시켜 실행합니다.
즉, 비동기 작업은 queue에서 대기하다가 stack에 더 이상 진행하는 작업이 없을 때 스택으로 이동되어 실행되는 방식입니다. 이 덕분에 비동기적으로 작업을 처리할 수 있게 되었습니다.
이렇게 이벤트 루프를 이용하여 비동기 작업을 관리하고, Promise와 async/await를 활용하여 비동기 코드를 더욱 효과적으로 작성할 수 있습니다.
XMLHttpRequest 객체는 클라이언트와 서버 간의 데이터를 주고받기 위한 JavaScript의 내장 객체입니다. XMLHttpRequest 객체를 사용하여 비동기적으로 서버에 HTTP 요청을 보내고 응답을 처리할 수 있습니다. XMLHttpRequest 객체는 브라우저의 웹 페이지 내에서 동적으로 데이터를 업데이트하고, AJAX(Asynchronous JavaScript and XML) 패턴을 구현하는 데 주로 사용됩니다. XMLHttpRequest 객체는 이벤트 핸들러를 사용하여 응답의 상태 변화를 모니터링하고 데이터를 처리할 수 있습니다.
AJAX는 비동기적인 웹 애플리케이션 개발을 위한 패턴이며, XMLHttpRequest 객체를 사용하여 네트워크 통신을 수행하는 기술적인 접근 방식입니다. AJAX 패턴은 클라이언트와 서버 간에 데이터를 비동기적으로 주고받을 수 있도록 해주는 기술적인 개념을 의미합니다.
XMLHttpRequest 객체를 사용하여 데이터를 비동기적으로 요청하고 응답을 처리하는 것이 AJAX의 핵심 아이디어입니다. 이를 통해 웹 페이지의 일부분을 동적으로 업데이트하거나 서버와의 데이터 교환을 할 수 있습니다. AJAX 패턴은 사용자 경험을 향상시키고 웹 애플리케이션을 보다 반응형으로 만들기 위해 사용됩니다.
AJAX 자체는 개발자가 JavaScript와 XMLHttpRequest 객체를 사용하여 비동기 작업을 수행하는 패턴이며, AJAX를 더 편리하게 사용할 수 있는 기술에는 jQuery, Axios 라이브러리, JS 내장 API인 Fetch 메소드 등이 있습니다.
Fetch API는 네트워크 요청을 보내고 응답을 처리하기 위한 JavaScript의 인터페이스입니다. Fetch API는 HTTP 요청을 보내고 응답을 비동기적으로 처리할 수 있습니다. 주로 JSON, XML, HTML 등의 데이터를 가져오거나 전송하는 데 사용됩니다. Fetch API는 Promise 기반의 인터페이스를 제공하여 비동기 작업을 처리하고, Response 객체를 통해 응답 데이터를 다룰 수 있습니다.
하나의 목적을 가진 코드들은 서로 뭉쳐있어야, 코드 흐름과 목적을 파악하기 쉽습니다.
하나의 함수는 하나의 작업만을 수행해야 합니다. 그래야 차후에 새로운 기능이 추가되거나, 네이밍 단계에서 효율적으로 작업할 수 있습니다.
함수의 세부구현 단계의 코드가 공통화되고, 재사용할 수 있어야 합니다. 따라서 핵심 기능과 비핵심 기능을 나눠서, 필요한 만큼만 로직을 노출시켜야 하죠.
핵심 데이터는 밖에서 받아오는 형식으로 모듈을 구현합니다. 그 외의 세부구현은 모듈 안에 담아서 숨깁니다. 개발자가 받아오는 핵심 데이터만 보고도 이 모듈이 어떤 목적을 가진 것은 파악할 수 있어야 합니다.
상황에 맞게 추상화 단계를 조절해서 만드는 것이 중요합니다.
선언형 프로그래밍 : 어떤 동작을 할지 선언을 해놓고 핵심 정보만 받을 수 있게 한 것 -> 응집도와 재사용성을 고려해야 하는 곳에서 사용
명령형 프로그래밍 : 어떤 동작을 할지 일일히 명령을 적어주는 것 -> 세부 구현 단계에서 사용