728x90

이미지의 width, height와 같은 정보는 이미지 load이전에 알 수 없다. (로드전에 값 할당은 할 수 있다.)

onload가 되고나서야 값을 가져올 수 있는데 이렇게 onload이후에 값을 가져오는 방법은 다음과 같다.

See the Pen by korkt-kim (@korkt-kim) on CodePen.

'Javascript' 카테고리의 다른 글

Image Lazy Loading  (0) 2021.07.24
prototype  (0) 2021.02.14
var vs let (const)  (0) 2021.01.13
비동기 처리 - async/await  (0) 2020.12.27
비동기 처리 - Promise  (0) 2020.12.20
728x90

Lazy Loading 이란?

일반적으로  웹페이지는 사용자가 페이지를 열면 전체 페이지의 내용이 한번에 다운로드 되어 레더링이 이루어진다.

 

페이지의 내용이 매우 길고 사용자가 페이지 상단의 내용에만 관심이 있다면,

페이지 하단의 내용의 로딩까지 소비한 시간과 통신비용은 낭비가 된다.

 

사용자가 실제 이미지들이 실제로 화면에 보여질 필요가 있을때 비로소 해당 이미지의 로딩을 시작하는 것을 lazy lading이라고 한다.

lazy loading을 실현함으로써 페이지의 로딩시간과 통신비용을 줄일 수 있게된다.

 

Intersection Observer

사용자가 페이지를 보는지 혹은 보고있지않은지 observe 한다. 

 

다음은 사용자의 스크롤 움직임에 따라 사용자가 보고있는 section에 노란색 바탕을 채우도록 만든 코드이다. (threshold: 0.1) 보고있지 않으면 노란색 바탕은 해제된다.

See the Pen by korkt-kim (@korkt-kim) on CodePen.

callback function

  • 사용자가 특정 section을 보고있는지(intersecting)의 여부가 바뀔때마다 observe callback funtion이 실행된다
    • 현재 intersecting 여부는 entry.isIntersecting의 true/false값으로 판별한다.
  • observer : 특정 node를 observe하는 observer 자기 자신의 instance. 

options

  • options없이 기본적인 intersection observer는 viewport안에 node의 변화가 있을때마다 callback 함수를 실행시키기 때문에 무거운 감이 있다. 이를 해결하기위해 options를 사용한다.
  • root: intersecting 영역을 지정한다. observer를 동작시키기 위해서는 당연히 타겟의 조상 node element여야한다.
    default는 { root: null; } 이다. 이는 브라우저의 viewport를 intersecting 영역으로 삼겠다는 것이다.
  • threshold: section이 root element 기준 얼마 비중으로 들어와야 callback 함수를 실행할지 설정한다. 0~1의 값을 가진다.
  • rootMargin : root element안에서 intersecting 영역의 범위(px)를 설정한다. default는 0이다. "-150px" 이라면 현재 intersecting중인 페이지에서 동서남북 각각 안쪽으로 150px씩 움직인 범위안에서 intersecting여부를 찾게 된다.

lazy loading

그럼 이제 사용자가 특정 이미지를 intercept중일때만 해당 image를 로드하도록 lazy loading을 구현해보자

 

See the Pen by korkt-kim (@korkt-kim) on CodePen.

 기본적인 원리는 다음과같다.

  1. 초기에 이미지가 바로 load 못하도록 img 안 src attribute를 설정하지않는다. 여기서는 data-src로 이미지 url을 설정했다.
  2. 각 이미지 별로 intersection을 설정한다.
  3. 특정 이미지의 isIntersecting이 감지되면 해당 이미지의 data-src의 value를 src의 value로 설정해준다. 이제 해당 이미지는 load를 시작할 것이다.
  4. isIntersecting의 이미지는 이제 로드가 완료되어 더이상 observe할 필요없으므로 unobserve해준다

'Javascript' 카테고리의 다른 글

await event  (1) 2021.07.30
prototype  (0) 2021.02.14
var vs let (const)  (0) 2021.01.13
비동기 처리 - async/await  (0) 2020.12.27
비동기 처리 - Promise  (0) 2020.12.20
728x90

prototype은 ES6 이전 class 키워드가 존재하지 않았을 때까지 javascript코드를 객체지향적으로 구현하기위해 사용하였다.

prototype으로 객체를 정의할 수 있음은 물론 상속을 구현할 수도 있었기 때문에 class의 대체가 되었지만,

많은 객체지향언어에서 class의 개념이 완벽히 고정되어 많은 개발자들 사이에서도 class가 사용하기 편한 세상이 되었기 때문에 ES6부터 class를 지원하게 되었다.

ES6이후에도 class를 사용하면 기본적으로 해당 class안에 정의된 함수는 prototype에 정의된다. javascript의 class 지원은 개발자의 편의성을 위한 것이지 여전히 javascript는 prtotype based language인 것이다.

객체지향 언어의 개념(class의 개념)을 알고 있다면 prototype에 대한 이해는 쉬울 것이다.

차이점이라곤 객체를 함수를 통해 정의한다는 것 뿐이다.

이제부터 prototype을 프로토타입 자신을 통해 만들어질 객체의 원형이라고 생각하자.

class vs prototype

class

다음과 같이 선언된 class가 있다.

let PersonC = class {
  constructor(nm,id){
    this.name = nm;
    this.id = id;
  }
  getDetails(){ // exist on prototype of PersonC
    return `${this.name} :: ${this.id}`
  }
}

let bob = new PersonC('Bob',123); 
console.log(bob.getDetails(),bob.name); // Bob :: 123 Bob

let EmployeeC = class extends PersonC{ //EmployeeC prototype links to PersonC prototype
  constructor(nm,id,salary){
    super(nm,id);
    this.salary = salary;
  }
  employeeInfo(){ // exist on prototype of EmployeeC
    return `${this.name} :: ${this.id} :: ${this.salary}`;
  }
}

let noomi = new EmployeeC('Noomi',456,800);
console.log(noomi.employeeInfo()); //  Noomi :: 456 :: 800

먼저 class로 구현된 PersonC의 구조를 보자. 앞에서 말했듯이 javascript는 prototype based language이기 때문에 prototype으로 재정의되어 저장되어있다.

class 안에 getDetails는 prototype에 저장되어있다. 이렇게 class 안에 선언된 메서드는 prototype에 저장되게 된다.

PersonC 를 상속받고 있는 EmployeeC의 구조는 복잡하다. 하지만 한가지만 알면된다. PersonC의 getDetails 가 선언된 장소가 prototype안에 constructor안에 prototype 안에 있다. 이 의미는 바로 EmployeeC 클래스 안에 getDetails 메서드가 override 되어있지 않으면 getDetails 메서드의 정의를 찾을 때까지 prototype을 깊게 탐색한다는 것이다.

만약 EmployeeC에 getDetails 메서드가 override되어 있었다면 해당 getDetails 메서드를 호출할 것이다.

new means call this function as a constructor changing context

prtotype

위의 class로 구현된 부분을 똑같이 prototype으로 구현해보겠다.

let PersonP = function(nm,id){
  this.name = nm;
  this.id = id;
}

PersonP.prototype.getDetails = function() {
  return `${this.name} :: ${this.id}`;
}

let fred = new PersonP('Fred',321);
console.log(fred.getDetails(),fred.name); // Fred :: 321 Fred

let EmployeeP = function(nm,id,salary){
  PersonP.call(this,nm,id);
  this.salary = salary;
}

Object.setPrototypeOf(EmployeeP, PersonP.prototype); //extends,EmployeeP prototype links to PersonP prototype

EmployeeP.prototype.employeeInfo = function(){
  return `${this.name} :: ${this.id} :: ${this.salary}`
}

let mary = new EmployeeP('mary',345,100);
console.log(mary.employeeInfo()); // mary :: 345 :: 100

prototype에는 extends 키워드가 존재하지 않기때문에 상속을 구현하기 위해서는 setPrototypeOf 키워드를 사용한다.

class에서 사용하던 super도 없기때문에 super대신 상속받은 상위 객체의 cosntructor를 직접 호출하여 prototype변수를 초기화한다.

prototype 객체안에 객체를 선언하기 위해서는 class선언 결과에서 보았듯이 객체의 prototype에 함수를 직접 정의하면된다.


prototype object & prototype link

prototype은 prototype object, prototype link 이 두가지의 개념으로 구성되어있다.

prototype object

함수형으로 객체를 정의할때 Object 타입의 prototype을 부여받는다. 다음 예제를 통해 prototype object가 어떤 구조를 가지고 있는지 보도록하자.

function Person(){}

Person 객체 정의시

Person 객체Person 함수의 프로토타입 객체가 생성되며

각 객체는 서로 연결 되어 있다.

위의 구조가 어떤의미를 가지고 있는지 알아보도록 하자.

  1. new를 통해 해당 함수에 constructor(생성자) 자격을 부여한다
  2. 해당 함수의 prototye object 생성 및 연결
    • 함수의 prototype은 prototype object를 연결하고 prototype object의 constructor는 함수를 가르키기 때문에 prototype object또한 하나의 property처럼 변수 또는 함수를 추가하며 자유롭게 이용 가능하다.
    • __proto__로 prototype link이며 상속의 개념을 가지도록 하였다.

prototype link

함수 생성시 prototype object에서 같이 정의 되었던 __proto__이다.

prototype내에 선언된 변수 또는 함수를 객체가 직접 prototype object에 들어가지 않아도 참조할 수 있게 해주는 역할을 한다.

__proto__는 객체가 생성될때 조상이었던 함수 Prototype Object를 가르킨다. 위의 예제에서 __proto__는 Object Prototype Object를 가르킨다.

javascript는 기본적으로 본인이 가지고 있지않은 변수 또는 메서드를 찾을때까지 __proto__를 타면서 하위 prototype부터 최상위 prototype까지 훑어 올라간다.

Object는 항상 prototype object의 최상위 객체이다.

이것이 상속의 개념이 토대가 되며 상속은 보통 \_\_proto\_\_를 직접 선언해서 정의한지않고 setPrototypeOf 함수를 이용하여 상속을 정의한다.

'Javascript' 카테고리의 다른 글

await event  (1) 2021.07.30
Image Lazy Loading  (0) 2021.07.24
var vs let (const)  (0) 2021.01.13
비동기 처리 - async/await  (0) 2020.12.27
비동기 처리 - Promise  (0) 2020.12.20
728x90
  var let(const)
scope function-scope block-scope
hoisting yes no
global-object yes no
redeclaration yes no

1. function scope vs block scope

javascript에서 scope란 변수가 사용될 수 있는 범위를 뜻한다.

이를 근거로, function scope란 변수가 활용될 수 있는 범위가 function임을 뜻하고

block scope는 변수가 활용될 수 있는 범위가 { }(block)임을 뜻한다.

 

var로 선언된 변수는 function scope 속성을 가지고 있어 선언된 function 내에서라면 어디서든 사용할 수 있는 반면

let(또는 const)로 선언된 변수는 block scope 속성을 가지고 있어 선언된 block 내부에서밖에 사용할 수 없다.

See the Pen scope by zakelstorm (@zakelstorm) on CodePen.

2. Hoisting

hoisting은 변수가 초기화 되는 시점과 관련되어있다.

어떤 변수에 hoisting이 발생했다면 이는 코드 시작점에서 해당 변수가 undefined로 초기화 되었음을 뜻한다.

 

var로 선언된 변수는 hoisting 속성을 가지고 있어 선언된 function 내부에서라면 선언되기 이전이라도 사용될 수 있다.

반면에 let(또는 const)으로 선언된 변수는 hoisting 속성을 가지고 있지 않아 선언된 시점에 초기화되기 때문에 선언된 시점 이후부터 사용될 수 있다. 

See the Pen hoisting by zakelstorm (@zakelstorm) on CodePen.

3. create global object property

global object란 window object에 저장되어 있어 어디서든 사용가능한 object안 value를 뜻한다.

예를들어 대표적인 global object 중 하나는 alert가 되겠다.

 

코드의 top level에서 var로 선언된 변수는 global object가 되는 속성을 가지고 있어 전역변수 처럼 어디서든 쓸 수 있다. let으로 선언되었거나 함수 내부에서 선언된 var 변수는 window object에 추가되지않는다.

 

See the Pen global object property by zakelstorm (@zakelstorm) on CodePen.

4. Redeclaration

var 변수는 재선언이 가능하다.

반면 let변수는 재선언이 불가능하다.

var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.

let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared

'Javascript' 카테고리의 다른 글

Image Lazy Loading  (0) 2021.07.24
prototype  (0) 2021.02.14
비동기 처리 - async/await  (0) 2020.12.27
비동기 처리 - Promise  (0) 2020.12.20
동기/비동기 처리 - Callback, Callback 지옥  (0) 2020.12.20
728x90

복잡한 then chaining도 코드를 난잡하게 만들기 마련이다.

그래서 Promise를 좀 더 간결하고 간편하고 동기적으로 실행되는 것처럼 보이게 만들어주는 syntactic sugar로 async/await 을 사용한다

syntactic sugar란?
  • 사람이 이해 하고 표현하기 쉽게 디자인된 프로그래밍 언어 문법

  • 사람이 프로그래밍 언어를 sweeter하게 사용 할 수 있도록 도와주는 문법

  • 더욱 더 간결하고 명확하게 표현이 가능한 문법

// 비동기 처리를 하지 않은 경우
function fetchUser(){
	//do network request in 10 sec
    return 'asdf'
}

const user  = fetchUser();
console.log(user);

이 경우 javascript는 기본적으로 동기적으로 코드를 실행하기때문에

network작업이 promise가 아닌 경우라면 10초를 기다린 후 console log에 asdf를 띄우게 된다.

화면을 띄운다고 할때 이렇게 기다린 후 출력하는 것은 매우 비효율적이기에 우리는 그동안 Promise로 이러한 현상을 해결해 왔다.

 

// async
async function fetchUser(){
	//do network request in 10 sec
    return 'asdf'
}

const user  = fetchUser();
console.log(user);

async를 도입하였다. async를 사용하는 방법은  함수 앞에 async를 붙이면 끝이다.

이 경우 이 함수는 자동으로 Promise를 반환하는 함수가 된다.

 

// await
function delay(ms){
	return new Promise(resolve=>setTimeout(resolve,ms));
}

async function getApple(){
	await delay(3000);
    return 'apple'
}

async function getBanana(){
	await delay(3000);
    return 'banana';
}

/* then을 사용했다면
function getBanana(){
  delay(3000).then(()=>{
  	return 'banana';
  });
}
*/
	

 async가 Promise를 대신했다면 await는 then을 대신한다.

직관적으로 then을 썼을때보다 이해하기 편하다.

 

// async await 도입
async function pickFruits(){
	const apple = await getApple();
	const banaa = await getBanana();
    return `${apple} + ${banana}`;
}

pickFruits().then(console.log);

Promise/then을 대신하여 async/await을 도입한 경우이다. 이 경우 총 6초를 기다린후 `apple + banana` 를 반환받게 된다.

하지만 getApple()과 getBanana()는 서로 독립적인 함수이므로 서로를 기다려 반환 받을때까지 6초씩이나 걸릴 필요가 없다. 이러한 문제를 어떻게 처리할 수 있을까 방법은 다음과 같다.

 

async function pickFruits(){
	const applePromise = getApple();
    const bananaPromise = getBanana();
    const apple = await applePromise();
    const banana = await bananaPromise();
    return `${apple} + ${banana}`
}

pickFruits.then(console.log);

이전 시간에 Promsie는 선언과 동시에 실행된다고 배웠다. 이러한 Promise의 특성을 이용하여

getApple()과 getBanana()를 일단 동시에 실행시킨후 ( await(then) 을 붙이지 않은 Promise이기 때문에 서로를 기다리지 않는다)

뒷 줄에 이 실행 시킨 함수들이 각각 return 값 반환 할때까지 기다린다.

그 이 후 성공적으로 3초만 기다린 후 `apple + banana`를 반환한다.

 

그렇다면 만약 이런 병렬적으로 처리해야할 함수가 많다면 각 함수마다 일일히 이런 방식으로 처리해줘야할까?

이 경우 Promise의 내재함수를 사용하면 쉽게 해결 할 수 있다.

 

function pickAllFruits(){
	return Promise.all([getApple(),getBanana]);
    .then(fruits => fruits.join(' + '));
}

pickAllFruits().then(console.log);

Promise.all은 병렬적으로 실행해도 되는 Promise 함수를 동시에 실행하여 모든 return값을 반환받을때까지 기다린 후 then을 실행한다.

만약 Promise 함수중 하나라도 error(reject)가 발생하면 다른 응답을 기다리지 않은채 catch 구문으로 가게된다.

만약 이것이 싫고 모든 값을 반환받을때까지 기다리고 싶다고 한다면 Promise.all 대신 Promise.allSettled를 사용하면된다. 

'Javascript' 카테고리의 다른 글

prototype  (0) 2021.02.14
var vs let (const)  (0) 2021.01.13
비동기 처리 - Promise  (0) 2020.12.20
동기/비동기 처리 - Callback, Callback 지옥  (0) 2020.12.20
ECMA Script 2020 (ES11)  (0) 2020.12.13
728x90

callback을 대체하여 비동기를 간편하게 처리할 수 있도록 도와주는 object.

정해진 장시간의 기능을 시행하고나서 정상적으로 동작했다면 성공 메시지 전송, 실패했다면 에러 메시지 전송.

 

promise는 두가지 포인트만 알고 가면 이해하기 편하다

  1. state : 시행하고 있는 중인지, 성공했는지 실패했는지의 상태 (pending -> fulfilled or rejected)
  2. producer & consumer : 정보를 제공하는 producer(promise 생성) 소비하는 consumer(promise 실행)로 나눌 수 있다.

Producer

새로운 Promise는 생성되는 순간, 안에 있는 executer callback function을 자동으로 실행하게 된다. 

See the Pen Promise by zakelstorm (@zakelstorm) on CodePen.

위의 상황에서 먼저 첫번째 경우를 보면 다음과 같은 특징을 가지고 있다.

  1. new Promise가 선언됨 시점에서 Promise내부의 callback함수가 실행됨.
  2. promise.then을 3번 호출해도 Promise내부의 callback함수가 실행되지 않음.

이와 같은 특징에서

Promise는 외부에서 선언과 동시에 callback 함수가 실행이 되며

이 Promise 선언을 대입받은 변수(promise)는 Promise가 resolve 한 값을 받게 되어 해당 변수에 then을 붙여 실행하여도 기다림 없이 then의 callback함수를 실행하게 된다.

 

이를 사용자가 원하는 시점에 Promise를 실행하고 원하는 then callback함수 실행 시점을 만들기 위해

코드의 두 번째 경우에서 처럼  Promise를 함수에 감싸 함수 실행하듯 사용하면 위의 문제를 해결할 수 있다.

Consumer

실행된 promise에 대해 then, catch, finally를 이용하여 resolve 또는 reject 된 값을 가져올 수 있다.

resolve와 reject는 각각 then, catch에 대응되며 사용방법은 다음과 같다.

const producer = new Promise((resolve,reject)=>{
  console.log('doing someting...')
  setTimeout(()=>{
    resolve('success');
  },2000)
})

producer.then(value=>{
  console.log(value); // resolve value인 'success'를 출력
})

const producer2 = new Promise((resolve,reject)=>{
  console.log('doing someting...')
  setTimeout(()=>{
    reject('fail');
  },2000)
})

producer2.then(value=>{
  console.log('then') //성공적인 case만 출력하므로 then구문은 타게되지않는다.
  console.log(value); 
}).catch(value=>{
  console.log('catch') // reject되는 순간 catch 구문을 타게된다.
  console.log(value);// resolve value인 'fail'를 출력
})

then은 promise를 반환하기 때문에 이 뒤에 catch 또는 then을 또 한 번 호출할 수 있다. 이를 chaining이라고 한다.

 

Promise chaining

const fetchNumber = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1),1000
  })
})

fetchNumber
  .then(num => num*2) // 2, num*2 앞에 (return)이 생략되어 있다
  .then(num=>num*5) // 10
  .then(num=>{
    return new Promise((resolve,reject)=>{
      setTimeout(()=>{
        num-=7; 
        resolve(num); // 3
      },1000)
    })
  })
  .then(num=>{
    console.log(num) // 3
  })
;

then은 일반적인 return 또는 promise resolve를 바로 전달할 수 있다. (then 또한 Promise 값을 return 하기 때문)

이러한 점덕분에 위 코드에서 (return) num 또는 resolve(num) 값이 뒤의 then으로 넘어간 것이다.

 

Error Handling

const getHen = () =>{
	new Promise((resolve,reject)=>{
    	setTimeout(()=>resolve('myhen'),2000);
    });
}

const getEgg = (hen) =>{
	new Promise((resolve,reject)=>{
    	setTimeout(()=>reject(`${hen} => myegg`),2000);
    });
}

const cook = (egg) =>{
	new Promise((resolve,reject)=>{
    	setTimeout(()=>resolve(`${egg} => myfried egg`),2000);
    });
}
 
 // return값을 그대로 한개의 함수로 바로 넘긴다면 다음과 같이 parameter생략가능
 getHen
   .then(getEgg)
   .then(cook)
   .then(console.log) //어떠한 것도 출력되지않음
   
 getHen
   .then(getEgg)
   .then(cook)
   .then(console.log)
   .catch(console.log) // Error메시지와 함께 myhen => myegg 출력
   
 //전체적인 promise chain에 문제가 생기지 않도록
 getHen
   .then(getEgg)
   .catch(error =>
   	return 'mybread'
   )
   .then(cook)
   .then(console.log) // mybread => myfried egg 출력
   .catch(console.log) 

catch는 이전의 Promise chain에서 reject 반환 시 실행되는 구문이다.

 

javascript에서는 catch의 위치를 적절히 대입하여 error에 대응할 수 있다.

catch 구문 뒤의 then은 앞의 catch 구문에서 에러를 처리한 후에도 계속 이어서 실행되며,

catch 뒤의 catch의 실행 시점은 앞의 catch와 뒤의 catch사이에서 error가 생겨야 비로소 실행이 된다.

 

Callback 지옥 해결

이전의 Callback지옥을 해결한 버전은 다음과 같다. then을 중첩해서 쓰는 과오를 범했었는데 then을 중첩해서 쓰면 callback지옥과 결국 비슷한 의미가 된다. 가능한 떨어뜨리도록 하자.

See the Pen VwKrEOw by zakelstorm (@zakelstorm) on CodePen.

'Javascript' 카테고리의 다른 글

prototype  (0) 2021.02.14
var vs let (const)  (0) 2021.01.13
비동기 처리 - async/await  (0) 2020.12.27
동기/비동기 처리 - Callback, Callback 지옥  (0) 2020.12.20
ECMA Script 2020 (ES11)  (0) 2020.12.13
728x90

Synchronous vs Asynchronous

Synchronous

기본적으로 자바스크립트는 Synchronous 하다.

그러므로 hoisting(var, function declaration을 제일 위로 올리는 것) 후 코드를 한줄한줄 순서대로 실행한다.

Asynchrous

Asynchrous 코드는 언제 실행될지 예측할 수없다.

예를 들어 setTimeout 함수 안에 하나의 파라미터 인자로 만든 함수를 전해준다. 당장 실행하지 않고 브라우저에게 일정 시간이 지난 후 callback을 실행하게 해주는 기능이 내재되어있다. 이것이 asynchrnous execution의 기본이다.


Synchronous callback function vs Asynchronous callback function

callback function은 모두 asynchronous할까?

그렇지 않다.

 

callback function에도 callback function을 바로 실행하는 synchronous callback function과

callback function이 언제 실행될지 예측할 수 없는 asynchronous callback function이 존재한다.

See the Pen Synchrnous vs Asynchrnous by zakelstorm (@zakelstorm) on CodePen.


callback 지옥

callback function이 중첩적으로 쓰여 callback이 매우 nesting 된 형태. callback 안에 callback이 있고 그 callback 안에 또 callback이 있는 매우 알아보기 힘든 코드. 이를 유지할 시 유지 보수력이 떨이지게 된다.

 

callback 지옥의 코드를 만들어보았다.

로그인 기능을하는 frontend 코드이며, backend가 존재하지 않기때문에 해당 비동기 처리는 setTimeout( )으로 대체하였다.

 

코드의 구성은 다음과 같다.

  1. 사용자가 id, password 입력
  2. 입력된 id, password로 login (loginUser이용)
  3. login 이후 바로 해당 id의 role 반환(loginUser 함수 안에 onSuccess 이용)
  4. 반환된 role 출력 (getRoles 이용)

See the Pen callback 지옥 by zakelstorm (@zakelstorm) on CodePen.

callback function이 어떻게 돌아가는지 확실히 알기 위에서는 코드를 일반적으로는 우리가 머릿속에 코드를 외우기 힘들기 때문에 왔다갔다해서 봐야할 것이다. 이유는 다음과 같다.

  • loginUser
    • loginUser안 onSuccess에는 user=>{ userStorage1.getRoles(user, ... , ...) } 가 대입된다.
    • onSuccess에서는 id를 parameter로 쓰고있다. 즉, callback function의 user에 id가 대입된다.
  • getRoles
    • getRoles안 onSuccess에는 userWithRole=>{ alert(...); }가 대입된다.
    • onSuccess에서는 {name:'ASDF', role:'admin'}을 parameter로 쓰고있다. 즉, callback function의 userWithRole에 {name:'ASDF, role:'admin'}이 대입된다.

이렇게 대입 방향이 실행 코드(loginStorage1)~정의 코드(loginStorage)사이에서 엉키게 된다.

callback function에 parameter가 존재하면, 코드를 이해하기 위해서는 계속 실행코드와 정의코드로 왔다갔다 해야한다. 이러한 callback function이 nesting 되는 형태가 복잡하다면 이것이 콜백 지옥이다.

 

이를 해결하는 방법이 바로 Promise와 async/await 이다. return 값이 생기게 됨으로서 대입 방향을 단방향으로 만들게 된다.

 

'Javascript' 카테고리의 다른 글

prototype  (0) 2021.02.14
var vs let (const)  (0) 2021.01.13
비동기 처리 - async/await  (0) 2020.12.27
비동기 처리 - Promise  (0) 2020.12.20
ECMA Script 2020 (ES11)  (0) 2020.12.13
728x90

ES6와 비교하여 ECAM Script 2020(ES11)에서 새로 생긴 문법은 다음과같다.

  1. BigInt
  2. Import
  3. Promise.allSettled( )
  4. globalThis
  5. Nullish Coalescing Operator
  6. Optional Chaing Operator

BigInt

ES6에서 int 의 범위는 +/- 2^53 - 1(=9007199254740991) 이었다.

※ 9007199254740992까지 출력이 가능하지만 9007199254740992나 9007199254740993이나 9007199254740992로 출력되기때문에 reliable 하지않아 제외.

ES11에서 새로운 Number표현법인 BigInt가 도입됨에 따라 숫자의 max min의 제한이 사라지게 되었다.

사용법은 숫자뒤에 n을 붙이거나 BigInt로 숫자또는 숫자문자열을 감싸면 된다.

Number에서 사용할 수 있던 연산자(+,-,*./,||,&&...)를 똑같이 사용할 수 있다.

See the Pen ES11 - BigInt by zakelstorm (@zakelstorm) on CodePen.

BigInt가 가지는 Number와의 차이점은 다음과 같다.

  • Math object의 함수와 사용될 수 없다.

    • Cannot convert a BigInt value to a number
  • Nubmer와 연산에 함께 사용될 수 없다. 사용하기위해서는 Number를 BigInt로 (또는 BigInt를 Number로) 캐스팅 해야한다.

    • Cannot mix BigInt and other types, use explicit conversions

Import

ES11부터 import는 promise를 return 한다. 따라서 async/await 로 함수 내부 코드의 동기 처리가 가능하다.

const helpModule = './helper.js';
import(helpModule).then((module)=>{
  module.doStuff1();
  module.doStuff2();
})

(aysnc function importCheck(){
  const helpModule = './helper.js'
  const module = await import(helpModule);
  module.doStuff1();
  module.doStuff2();
}) 

Promise.allSettled( )

promise.all 의 단점을 보완하기 위해 만들어진 Promise 함수.
기존 promise.all은 단 하나의 request라도 error 발생 시 그 뒤의 request를 기다리지 않고 다음 catch phrase를 시행하는 문제가 있었다.
이로 인해 어떤 request가 성공하고 실패했는지 알 수 없었고 마지막 request의 response를 기다린 후 시행되어야 할 코드를 만들기 어려웠다.(가능은 하다...)
promise.allSettled는 모든 request가 response를 받을때까지 기다린 후 다음 then phrase를 시행하도록한다.

이때 response에 error가 있더라도 then으로 가게되어 catch구문이 사실상 필요가 없게된다.

See the Pen ES11 - Promise.allSettled( ) by zakelstorm (@zakelstorm) on CodePen.


globalThis

window ,self, global 의 기능을 하는 변수이다.

Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}

다른 점은 window는 browser에서 사용.

selfwebworker에서 사용.

global은 node.js에서 사용.한다는 점이다.

이러한 각각의 환경에대한 특수성 때문에 이를 한 변수로 통일하고자 globalThis라는 변수를 ES11부터 사용할 수 있게 되었다.


Optional Chaining Operator (?.)

ES6까지는 undefined variable object의 key값 참조 시 발생하던 에러 때문에 Ternary Operator 또는 if 구문으로 예외상황에 대해 항상 준비해야했다.

ES11부터 이 예외상황에 대한 준비를 보다 간소하게 하기위해 operator를 만들었는데 이를 Optional Chaning Operator라고 한다.

Optional Chaning Operator가 존재함에 따라 variable object의 key값을 참조시 해당 변수가 undefined 라면 false를 return하게 된다.

const person1={ // nested Object
    name:'Ellie`,
    job:{
        title:`S/W Engineer`,
        manager:{
            name:'Bob',
        }
    }
}

const person2={
    name:'Bob',
};

function printManager(person){
    console.log(person.job.manager.name);
}
console.log(person1); //OK
console.log(person2); //ERROR. resolve with ternary Optional or if phrase

function printManagerES11(person){
    console.log(person.job?.manager?.name);
}

Nullish Coalescing Operator (??)

ES6 까지는 Boolean의 false, Object의 null,undefined, String의 '', Number의 0 은 모두 false로 인식되었다. 여기서 DB에서 참조했을 뿐인데 empty string이나 0 nubmer를 false로 규정하는 문제때문에 이 경우 true를 return 하도록 예외상황을 구분하는 코드를 작성해야했다.

ES11 부터는 이를 간소화 하고자 operator를 만들었는데 이를 Nullish Coalescing Operator라고 한다.

Nullish Coalescing Operator은

empty string과 0 number의 경우 true를 return 하도록 하고,

false,null,undefined의 경우에만 false를 returng하도록 한다.

//Logical OR operator  
// false: false, '' , 0, null , undefined  
const name='Ellie';  
const userName = name || 'Guest';  
console.log(userName);

const name = null;  
const userName = name || 'Guest';  
console.log(userName);

//문제가 생기게되는데 문자열이 비어있는 경우에도('') 아무런 이름쓰고싶지않은데 Guest 출력  
// false의 조건을 좀더 까다롭게 해주자 오직 false null undefined만 false로 인식

cosnt name = '';  
const userName = name ?? 'Guest';  
console.log(userName); //''

const num = 0;  
const message = num ?? 'undefined';  
console.log(message); //0

'Javascript' 카테고리의 다른 글

prototype  (0) 2021.02.14
var vs let (const)  (0) 2021.01.13
비동기 처리 - async/await  (0) 2020.12.27
비동기 처리 - Promise  (0) 2020.12.20
동기/비동기 처리 - Callback, Callback 지옥  (0) 2020.12.20

+ Recent posts