22-10-17-JavaScript(9) 비동기 프로그래밍

YJ·2022년 10월 17일
0
post-thumbnail

동기와 비동기

동기 - 순차적인 흐름을 가짐
	- 하나의 작업이 실행되는 동안 다른 작업들은 대기 상태
비동기 - 비순차적
	- 작업 순서를 기다리지 않고 바로 다음 작업 수행

비동기 처리

처리 완료되지 않아도 다음 코드 실행
데이터를 받아 온 후 코드 실행되는 경우 비동기 처리

자바스크립트는 싱글 스레드로 동작
웹이 발전하면서 단순 콜백만으로는 모든 상황 통제가 어려움
=> 비동기 처리 코드들을 동일한 api 형태로 사용할 수 있게 추가된 것이 Promise

비동기 처리 종류

Promise, await/async, fetch

Promise -> then, catch
await/async -> try-catch
fetch -> 접근하려는 url과 매개변수로 네트워크 요청 보냄

setTimeout()

for문 하는 동안 다른 일도 하고 싶다면(비동기) -> setTimeout 함수 사용
함수를 의도적으로 지연한 뒤 실행하고 싶을 때 사용하는 함수

선입선출 방식, 먼저 들어온게 먼저 나감

프로미스 Promise

JS의 오브젝트로 비동기적을 수행할 때 콜백함수 대신 사용

사용하는 이유?
=> 비동기 처리 코드를 표준 api 형태로 사용 가능하도록 추가
=> 비동기 코드를 promise 객체화 가능
=> 메소드 체인 형태로 callback depth 균일화
=> 프로미스로 생성된 비동기 인스턴스는 한 번만 실행 됨
=> 에러 분기를 catch로 전달
=> 비동기 처리에서 발생하던 안좋은 패턴을 개선할 수 있도록 도와주는 새로운 비동기 표준
const promise = new Promise((resolve, reject) => {
	// code
})
.then(result => result)
.catch(err => err)
.finally(result => result)
resolce : 일이 성공적으로 끝난 경우
reject : 에러 발생 시 에러 객체를 나타내는 에러와 함께 호출

프로미스 상태
- pending(대기) - resolve(해결) - fulfilled(이행)
- pending(대기) - reject(거부) - rejected(실패)

프로미스는 성공 / 실패만 해야함
resolve, reject 중 하나를 반드시 호출
let p = new Promise(function(resolve, reject){
	resolve('hello world');
}).then(메시지 => {
	alert(메시지)	// 'hello world'
  	return 메시지.split(' ')[0]
}).then(메시지 => {
	alert(메시지)	// 'hello'
  	return 메시지.split(' ')[0]
})
// reject는 rejected된 Promise를 반환
let p = new Promise(function(resolve, reject){
	// 비동기적으로 실행될 code 작성
	reject('hello world');
})
console.log(p);
// Promise {<rejected>: 'hello world'}
// rejected(실패)된 Promise를 catch로 받으면 fulfilled 반환
let p = new Promise(function(resolve, reject){
// 비동기적으로 실행될 code 작성
	reject('hello world')
}).catch(메시지 => {
	alert('catch 실행!!')
	return 'catch!!'
})
console.log(p)
// promise <pending>에서
// Promise {<fulfilled>:'catch!!'} 로 변경

then

프로미스 정상적 수행되어 resolve라는 콜백 함수 통해서 전달

프로미스에 then 호출하면 then은 결국 똑같은 프로미스를 리턴 -> catch를 다시 호출 가능
=> 프로미스 체이닝

catch

에러가 발생한 경우만 다루고 싶은 경우에 사용

finally

성공이든 실패이든 상관없이 무조건 마지막에 호출되는 메서드
어떤 기능을 마지막으로 수행하고 싶을 때 사용
promise
	.then(value => {
		console.log(value);
	})
	.catch(error => {
	  console.log(error);
	})
	.finally(() => {
		console.log('-제주맛집');
	});

error

// resolve 상태에서 중간에 error 발생한 경우
let p = new Promise(function(resolve, reject){
// 비동기적으로 실행될 code 작성
	resolve('hello world')
}).then(메시지 => {
	alert(메시지)
	return 메시지.split(' ')[0]
}).then(메시지 => {
	alert(메시지)
	throw Error('Error 발생! 경고경고!')
	return 메시지[0]
}).then(메시지 => {
	alert(메시지)
	return 메시지
}).catch(메시지 => {
	console.log(메시지)
	alert('catch 실행!!')
})

console.log(p)
let p = new Promise(function(resolve, reject){
	setTimeout(()=>resolve('끝났다!'),3000)
})
console.log('hello world')
console.log(p)

// hello world
// Promise {<fulfilled>: 3초 뒤에 끝났다!}

프로미스 체이닝

let p = new Promise(function(resolve, reject){
	setTimeout(()=> resolve(1),10000) // 10초
})
console.log('hello world');

let p2 = p.then(function(result){
	console.log(result); // 1
  	return result * 2;
})
console.log('hello world2');
let p3 = p2.then(function(result){
	console.log(result); // 2
  	return result * 2;
})
console.log('hello world3');
// hello world1
// hello world2
// hello world3
// 1
// 2

async function (async/await)

async function

프로미스의 문제점
=> 특정 조건에 따른 분기 나누기 어려움
=> 어디에서 에러 발생하였는지 파악 어려움
=> 가독성이 떨어져 .then 지옥 발생 가능

==> 해결 방법 async/await

프로미스 기반으로 동작
.then 없이 비동기를 동기처럼 동작 가능하도록 구현
// 함수 앞에 async 위치
async function 함수이름() {
	return 결과 값;
}
// async 함수는 항상 resolved 프로미스 값을 반환!!
.then() //을 통하여 반환값 바로 호출하여 사용 가능
/////////
let a = async function() {
	return 'hi';
}
a().then(console.log);
// 'hi'
// Promise {<fulfilled>: undefined}

///////
async function f() {
	return 'hello world';
}
console.log('!');
f()
.then(메시지 => {
	alert(메시지);
  	return 메시지.split(' ')[0];
})
.then(메시지 => {
	alert(메시지);
  	return 메시지.split(' ')[0];
})
console.log('!!');
// '!'
// '!!'
// hello world
// hello

awync & await

비동기 처리가 되어야 하는 부분 앞에 await 키워드 넣기
await 키워드는 async 안에서만 사용 가능하며
프로미스 앞에서 사용해야 함
async function f() {
	await 비동기처리메서드이름();
}

const one = () => Promise.resolve('one') 

async function f() {
	console.log('in function') // 3번
    const res = await one() // await 사용하면 프로미스를 반환할 때까지 기다리는 동안 비동기 함수 일시 중단 가능
    // await를 만나면 awync 함수 일시 중단됨
    console.log(res) 
}

console.log('before function') // 1번
f(); // 2번
console.log('after function') // 4번
// 비동기 awync 함수 f()가 일시 중단되어 await 엔진은 비동기 함수에서 나와 비동기 함수가 호출된
// 실행 컨텍스트에서 코드 계속 실행함
// 전역 실행 컨텍스트에서 더 이상 실행할 작업이 없는 경우 이벤트 루프는
// 큐에서 대기 중인 작업이 존재하는지 확인하여 f() 함수를 계속 실행함 => res 반환 ('one')

// 출력 결과
// before function
// in function
// after function
// one
async function f() {
	let promise = new Promise((resolve, reject) => {
    	setTimeout(()=> resolve('ok!'), 1000)
    });
  
  let result = await promise;
  alert(result);
}
f()
//  1초 후에 ok!

// 기다리지 않을 경우
let result = promise;
console.log(result);
// ok! 출력 안됨
// Promise {<pending>}
// Promise {<fulfilled>: undefined}
async function f() {

    let promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve("완료!"), 10000)
    });

    let result = promise; // await는 아니지만
    console.log(result);
    alert(result);
    return 'hello' // return으로 반환하는 경우
}

f();
// Promise {<pending>}
// Promise {<fulfilled>: 'hello'}
async function f() {

    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            alert("완료")
            resolve("완료!")
        }, 1000)
    });

    let result = promise;
    console.log(result);
    alert(result);
    return 'hello'
}

f();
// alert로 완료 뜸
// Promise {<pending>}
// Promise {<fulfilled>: 'hello'}

async function f() {

    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            alert("완료")
            resolve("완료!")
        }, 1000)
    });

    let result = await promise; // await 사용
    console.log(result);
    return 'hello'
}

f();
// Promise {<pending>}
// 완료!
profile
함께 배워나가고 싶습니다!

0개의 댓글