[TIL 2021.10.13] js.callback hell
45147 ワード
Today I Learned
youtube dream coding - js 10,11,12
Callback function, Promise
JSON to String and String to JSON in JS
youtube dream coding - js 10,11,12
Callback function, Promise
JSON to String and String to JSON in JS
地獄体験
'use strict';
// 자바스크립트는 동기적이다.
// 호이스팅 이후에 코드가 순서에 맞춰서 하나씩 동기적으로 실행된다.
// 호이스팅이란 var 변수와 함수 선언이 자동으로 제일 위로가는것을 호이스팅이라 한다.
console.log('1');
setTimeout(() => console.log('2'), 1000);
// 비동기적인 실행 나중에 실행하니까 콜백
console.log('3');
// 콜백은 항상 비동기일때만?
// ㄴㄴ
// 즉각적으로 실행하는 Synchronous callback
function printImmediately(print) {
print();
} // 이 함수는 호이스팅되어서 실제로는 제일 위에 선언 되었을 것이다.
printImmediately(() => console.log("hello"));
// 나중에 언제실행할지 예측되지않는 Asynchronous callback
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);
/**
* 자바스크립트는 콜백형태로 다른 인자에 전달할수도있고 변수에 할당할수도있다.
* 언어마다 다르다. 서브루틴, 람다식, 함수포인터를 활용하는 방법도 있다.
* 자바스크립트에서는 콜백함수를 위와 같이 활용한다.
*/
// -----------------------콜백 지옥 체험------------------------- //
class UserStorage { // 백엔드에서 데이터 불러오는 척하는 예제 클래스
loginUser(id, password, onSuccess, onError) {
setTimeout(() => {
if (
(id === 'kyu' && password === '1234') ||
(id === 'code' && password === 'squad')
) {
onSuccess(id);
} else {
onError(new Error('not found'));
}
}, 2000); // 로그인 하는데 2초 걸린다고 생각해보자
}
getRoles(user, onSuccess, onError) {
setTimeout(() => {
if (user === 'kyu') {
onSuccess({name: 'kyu', role: 'admin'});
} else {
onError(new Error('no access'));
}
}, 1000);
}
}
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your password');
userStorage.loginUser(
id,
password,
(user) => {
userStorage.getRoles(
user,
userWithRole => {
alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`);
},
error => {
})
},
(error) => {
}
);
/**
* 콜백 지옥의 문제점
* - 비즈니스 로직을 한번에 파악하기가 힘듦
* - 에러가 발생하거나 디버깅할때 해결하기가 힘듦
* - 내가 했던게 콜백지옥이었다는 것
*/
/**
* 해결법 - Promise
*/
Promise
'user strict';
// Promise는 Asynchronous operation을 위한 자바스크립트 객체이다
// State: pending -> fulfilled or rejected
// Producer vs Consumer
// 1. Producer
// Promise가 만들어지면 excutor가 자동으로 실해된다.
const promise = new Promise((resolve, reject) => {
// doing some heavy work
// 시간이 걸리는건 비동기적으로 해주는게 좋다. (네트워크, 파일 읽기)
console.log('doing something...');
setTimeout(() => {
// resolve('kyu');
reject(new Error('no network')); // Error는 자바스크립트 제공
/**
* 어떤 작업 이후에 성공하면 resolve 함수,
* 실패하면 reject(new Error...)를 반환한다.
* 반환한 것은 아래 Consumers 에서 받아 처리한다.
*/
}, 2000);
});
// 2. Consumers: then, catch, finally
promise
.then((value) => {
console.log(value);
})
.catch(error => {
console.log(error);
})
.finally(() => console.log('finally')
);
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(num => num * 2)
.then(num => num * 3)
.then(num => { // then에서는 값을 전달하거나 또다른 비동기인 Promise를 전달할수있다.
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num - 1), 1000);
});
})
.then(num => console.log(num));
// 4. 에러 핸들링
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('🐓'), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${hen}=> 🥚`), 1000);
});
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`, 1000));
});
getHen()
.then(hen => getEgg(hen)) // -> .then(getEgg) 받아서 바로 함수애 넣는 경우
// .catch(error => {
// return '🥖';
// }) reject() 된 것을 바로 처리할수 있도록 catch 할 수 있음
.then(egg => cook(egg)) // -> .then(cook)
.then(meal => console.log(meal)) // -> .then(console.log)
.catch(console.log);
Promiseでコールバック地獄を解決
'use strict';
class UserStorage { // 백엔드에서 데이터 불러오는 척하는 예제 클래스
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === 'kyu' && password === '1234') ||
(id === 'code' && password === 'squad')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
}, 2000); // 로그인 하는데 2초 걸린다고 생각해보자
});
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === 'kyu') {
resolve({ name: 'kyu', role: 'admin' });
} else {
reject(new Error('no access'));
}
}, 1000);
});
}
}
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your password');
userStorage
.loginUser(id, password)
.then(userStorage.getRoles)
.then(user => alert(`Hello ${user.name}, you have a ${user.role} role`))
.catch(console.log);
/**
* 아까 callback 안 callback 에서는 가독성이 매우 떨어졌지만
* Promise 를 사용하면서 간결하고 가독성이 좋아졌다.
*/
JSONについて
//JSON
// 1. Object to JSON
// stringify(obj)
let json = JSON.stringify(true); // boolean 타입도 변환 가능
console.log(json);
json = JSON.stringify(['apple', 'banana']);
console.log(json);
const rabbit = {
name: "less",
color: 'white',
size: null,
birthDate: new Date(),
jump: () => {
console.log(`can jump!`);
} // 함수는 JSON에 포함되지 않는것을 밑에 로그함수에서 확인 가능
}
json = JSON.stringify(rabbit);
console.log(json);
json = JSON.stringify(rabbit, ["name", 'color']);
console.log(json);
console.clear();
json = JSON.stringify(rabbit, (key, value) => {
console.log(`key ${key}, value: ${value}`);
return key === 'name' ? 'kyu' : value;
})
console.log(json);
// 2. JSON to Object
// parse(json)
console.clear();
json = JSON.stringify(rabbit);
const obj = JSON.parse(json);
console.log(obj);
rabbit.jump();
// obj.jump();
console.log(rabbit.birthDate.getDate());
Reference
この問題について([TIL 2021.10.13] js.callback hell), 我々は、より多くの情報をここで見つけました https://velog.io/@kyukim/20211013テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol