반응형

프로젝트를 진행하다보면 HTTP 통신을 통해 데이터를 가져와야할 경우가 있습니다. 기본적으로 HTTP통신은 비동기적으로 이루어집니다. 그렇다보니 데이터를 받아오기전에 Rendering이 이루어지는 경우도 있고 미리 연산처리를 해버려 에러를 발생시키는 경우도 빈번하게 발생합니다.

이번 포스팅에서는 위와 같은 일을 방지하기 위해 Javascript 에서의 비동기를 동기로 실행하는 방법에 대해서 알아보려합니다 👍

📋비동기 / 동기

우리는 카페에가서 음료를 주문하고 진동벨을 받아옵니다. 자리에가서 앉아 있다 진동벨이 울리면 커피를 받아옵니다. 이를 ‘비동기 처리’에 비유할 수 있습니다.

각자의 일을 처리하다 자신의 차례가 오면 자신의 일을 수행합니다. 서로에게 영향을 주지 않습니다.

진동벨이 없다고 생각해보세요 카페에가서 음료를 시키고 음료가 나올때까지 카운터에서 기다려야한다면 우리는 커피가 나오기전까지는 자리에 앉아 업무를 볼 수 없을거에요 이처럼 앞의 일이 끝나야 다음일을 처리할 수 있는 것을 ‘동기의 처리’에 비유할 수 있습니다.

📋비동기를 동기로 동작시키는법

자바스크립트에서의 비동기를 동기로 동작시키는 대표적인 3가지의 방법을 알아보겠습니다.

Callback Function

Promise

Async / Await

Generator (이 포스트에서는 다루지 않습니다)

📋 1. Callback

첫번째로 Callback을 이용한 방법을 알아보겠습니다.

기본적인 Callback의 사용법은 위와 같습니다 😉

a 는 callback 즉 function을 받는 함수입니다.

a 는 받은 함수에 ‘i am A’ 라는 값을 넣어줍니다.

b 는 a에서 넘겨준 ‘i am A’ 라는 값을 받아 console 에 찍어줍니다.

위의 코드의 동작을 이해하셨다면 비동기를 동기로 바꾸는 코드도 쉽게 이해하실 수 있습니다.

두개의 함수가 있습니다.

step1은 실행 후 2초가 걸리고, step2는 1초가 걸립니다.

우리는 step1이 실행되고 step2 가 실행되기를 바랍니다.

위의 코드를 실행해보면 우리가 원했던 결과가 나오지 않습니다.

step2 가 실행하고 step1 이 실행됩니다.

어떻게 하면 우리가 원하는대로 실행시킬 수 있을까요 ? 바로 ‘Callback’ 을 이용하면 됩니다.

step1 은 함수를 인자로 받는 함수입니다.

step1 은 받은 함수를 실행해주는 역할을 합니다.

우리가 의도한대로 step1 이 실행된 후 step2 가 실행됩니다.

위와 같은식으로 Callback을이용하면 비동기를 동기처럼 동작하게 할 수 있습니다.

하지만 지금은 함수가 2개 뿐이지만 함수가 많아질 수록 함수의 깊이가 깊어집니다. 표현방법 2 처럼 말이죠 함수안에 함수 함수안에 함수…. 그안에 또 함수 … 다들 한번쯤 들어보셨을만한 Callback Hell 이 되는 것이죠 .. 그래서 조금더 깔끔하게 처리할 방법이 필요했습니다.

그것이 2번째 방법인 Promise 입니다.

📋2. Promise

기본적인 Promise 객체의 사용법 입니다.

foo 는 Promise 객체를 Return 합니다. 그렇기 때문에 foo().then 처럼 이어갈 수 있습니다.

foo().then 에서 then은 foo의 동작이 마무리된 후 동작합니다. Promise resolve 안에 넣어준 값이 들어옵니다.

then 을 계속 이어쓸 수 있습니다

Callback 으로 해결했던 것을 Promise 로 변경해보겠습니다.

a는 Promise 객체를 반환합니다. 그렇기 때문에 a().then 을 통해 순서를 제어할 수 있습니다. then 은 a의 동작이 마무리된 후 실행됩니다.

a 가 실행되며 console.log(‘a run …..’) 이 제일 먼저 실행되고

resolve를 통해 then 으로 (str === ‘a run …..’) 을 넘겨줍니다.

a의 실행이 끝나고 then 에서 b를 실행하며 str을 넘겨줍니다. 이때 console.log(‘b run …..’) 이 찍히게 됩니다.

마지막으로 1초 후 console.log(‘넘겨받은 값: ’, str) 이 찍히게 됩니다.

또 여러개의 비동기 작업이 있을때 비동기 작업이 모두 완료된 후에 어떤 작업이 이루어져야 할때도 Promise를 이용할 수 있습니다.

2개의 작업이 있습니다. 한가지 작업은 1초가 걸리고 다른 한가지 작업은 2초가 걸립니다. 우리가 원하는 것은 두개의 작업이 ‘모두’ 마무리 된 후에 다른 작업이 이루어지기를 바랍니다.

Promise.all 에 [첫번째 Promise, 두번째 Promise] 의 형태로 넘겨주면 모든 Promise의 작업이 끝난후 then 에 결과값을 배열형태로 넘겨줍니다

어떤가요 Callback 보다는 편리해졌나요 ? 하지만 Promise 또한 깊이가 깊어진다면 가독성이 현저히 떨어질 수 있습니다. 사실 Promise를 사용하는데 보기가 너무 힘들고 불편한 현상이 생겼다면 (본인의 코드를 의심해봐야 될 수 있습니다…😉)

📋3. Async / Await

마지막으로 살펴볼 방법은 Async / Await 입니다.

Async /Await 은 말그대로 동작을 일시정지 시킨것처럼 보이게 해줍니다. Promise 나 Callback 보다는 직관적인 코드 패턴을 가질 수 있습니다. (Async 와 Promise 의 차이점에 대해서는 후에 포스트에서 다뤄볼 예정입니다)

async 함수 표현식을 이용합니다.

async 함수 내부에서는 promise 객체들의 순서를 await을 이용하여 순서 조절이 가능합니다.

foo 는 async 함수입니다.

foo 를 실행가된다면 console.log(‘foo run….’) 이 가장 먼저 찍히게되고 아래 await 을 만나게 됩니다.

promise() 은 Promise 객체입니다. promise() 을 실행하면서 console.log(‘promise run ….’) 이 찍히게 되고 2초 후에 resolve(10) 을 실행하게됩니다. 앞에서 살펴봤던 Promise 에서는 then으로 10 으로 들어가지만 await 을 이용하게되면 10 이 return 됩니다. 즉 const num = 10 이 됩니다.

promise() 종료 후 num 에 10이 들어오고 console.log(‘num’, 10) 이 실행된 후 종료됩니다.

📢마무리

비동기를 동기처럼 사용할 수 있는 3가지 방법에 대해서 알아봤습니다. 어떤 것이 좋고 어떤 것이 안 좋다고 말하기에는 저의 경험과 지식이 아직 부족하기도 하고 상황마다 필요한 것들이 다르기 때문에 감히 말할 수는 없습니다.

Promise와 Async 는 디버깅 시 에러가 걸리는 포인트가 다르기도 하고 개인의 취향에 따라 어떤 것이 더 보기 편하다 나쁘다 등등 굉장히 많은 이야기가 오가는 것으로 알고 있습니다. 이에 대한 이야기는 자료를 더 수집한 후 뒤에 포스터에서 정리해보려 합니다. 😉

-출처 https://medium.com/@appear.ko/javascript-async-to-sync-157c57208598

 

반응형
반응형

📢JAVASCRIPT THROW 예외처리

▼ 내용
throw 에 에러가 걸리면 이하 구문은 실행안하고 catch문으로 들어간다

💻코드

function getRectArea(width, height) {
  if (isNaN(width) || isNaN(height)) {
    console.log("시작 1");
    throw "Parameter is not a number!";
    console.log("시작 2");
  }
  console.log("시작 3");
}

console.log("시작 4");

try {
  getRectArea(3, 'a');
  console.log("시작 5");
}
catch(e) {
  console.log("에러22"+e);
  // expected output: "Parameter is not a number!"
}

//console.log 에러일경우
> "시작 4"
> "시작 1"
> "에러22Parameter is not a number!"

//console.log 정상일경우
> "시작 4"
> "시작 3"
> "시작 5"
반응형
반응형

📢 [JAVA] 리터럴과 형변환

📋 상수와 리터럴

▼ 상수 (constant) : 변하지 않는 수 (ex : final 등으로 사용)

▼ 리터럴 (literal) : 프로그램에서 사용하는 모든 숫자,값,논리 값 (ex : 숫자,10,3.14,true,'a')

모든 리터럴은 상수 풀 (constant pool)에 저장되어 있음

상수풀에 저장될 때 정수는 int (4byte) , 실수는 double (8byte) 로 저장됨.

12,345,678,900L 이렇게 큰 숫자의 경우 L 을 붙여 8바이트로 처리됨

위의 각 숫자들이 상수풀에 저장되어있다가 프로그래밍을 할때 바로 꺼내와서 사용

 

📋 형변환

▼ 서로 다른 자료형의 값이 대입되는 경우 형 변환이 일어남

묵시적 형 변환 (implicit type conversion):

 작은수에서 큰 수로 덜 정밀한 수에서 더 정밀한 수로 대입되는 경우

명시적 형 변환 (explicit type conversion) :

 변환 되는 자료 형을 명시 자료의 손실이 발생 할 수 있음

묵시적 형 변환의 경우 별다른 코딩은 안해도 되고 명시적 형변환의 경우 캐스팅을 해줘야함

💻코드1

byte bNum = 10;
int iNum = bNum; 
// byte 는 1바이트 int 는 4바이트 따라서 묵시적 형변환

System.out.println(bNum); //10
System.out.println(iNum); //10

int iNum2 = 2;
float fNum = iNum2; 
// 정수형보다 실수형이 더 크기떄문에 별도의 캐스팅없이 묵시적 형변환

System.out.println(fNum); //20.0

double dNum;
dNum = fNum + iNum;
//fNum은 float 형이기 때문에 iNum 은 float 형식으로 형변환 1번
//dNum (double형)으로 값을 넣어주기 떄문에 fNum , iNum  (double)형으로 형변환 2번
System.out.println(dNum); //30.0




int iNum = 1000; 
byte bNum = (byte) il
System.out.println(bNum); //-24
// byte는 2의-7승(-127) ~ 2의 7승(127) 까지 표현하기 때문에
// iNum의 데이터가 손실이 된다. 명시적 형변환

double dNum = 1.2;
float fNum = 0.9F; 

int iNum1 = (int)dNum1 + (int)fNum;
int iNum2 = (int)(dNum1 + fNum);
System.out.println(iNum1); //1
System.out.println(iNum2); //2
// 실수를 int로 형변환 하면 소수점이하 자리는 버림이 된다.
// 따라서 iNum1 은 1+0 이고 iNum2 는 2.1 에서 소수점을 버리게 된다.

📋 진법 변환

▼2진수 , 8진수 , 16진수 를 각 진법으로 쓰면

2진수 0b~~~ (ex: 0b1010)

8진수 0~~~~ (ex: 012)

16진수 0x~~~~ (ex: 0xA)

(대문자 소문자는 가리지 않습니다.)

💻코드2

int num = 10; 
int bnum = 0b1010;
int onum = 012;
int xnum = 0xA;

System.out.println(num ); //10
System.out.println(bnum ); //10
System.out.println(onum ); //10
System.out.println(xnum ); //10

위처럼 진법변환을 프로그래밍 코딩을 할수 있다.
 
반응형

'프로그래밍 > Java' 카테고리의 다른 글

JAVA - 인스턴스, 힙 메모리  (1) 2022.01.01
Java - 라운드 로빈 (Round Robin) 예제  (0) 2019.05.29
반응형

◎ 라운드로빈 자바예제 파일

▼ 쓰레드를 만들고 작업시간 분할시간을 정해서 출력해서 보여주게끔 간단하게 잔 예제이다.

package javaSchedule; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class Round_Robin { // WT (Wait Time) : 기다린 시간 // TT (Total Time ) : 총 걸린 시간 public static void main(String args[]) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Time Quantum 시분할시간을 정하세요(숫자입력): "); int q = Integer.parseInt(br.readLine()); System.out.println("작업할 프로세스의 수를 정하세요 (숫자입력): "); int n = Integer.parseInt(br.readLine()); int proc[][] = new int[n + 1][4];//proc[][0] AT array, [][1] - RT , [][2] - WT , [][3] - TT for(int i = 1; i <= n; i++) { System.out.println(i + " 번쨰 프로세스의 작업시간은? (Burst Time) (숫자입력): "); proc[i][1] = Integer.parseInt(br.readLine()); } System.out.println(); //total_time 계산 및 time_chart 배열 초기화 int total_time = 0; for(int i = 1; i <= n; i++) { total_time += proc[i][1]; } int time_chart[] = new int[total_time]; int sel_proc = 1; int current_q = 0; for(int i = 0; i < total_time; i++) { //선택한 프로세스를 time_chart의 현재 시간에 할당 time_chart[i] = sel_proc; //1 단위 시간당 CPU가 할당되었으므로 선택한 프로세스의 남은 시간을 1 씩 감소시킵니다. proc[sel_proc][1]--; //WT 와 TT 산출 for문 for(int j = 1; j <= n; j++) { if(proc[j][1] != 0) { proc[j][3]++;//만약 프로세스 실행이 완료되지 않은 경우 TT는 1씩 증가함 if(j != sel_proc)//프로세스가 현재 CPU에 할당되지 않은 경우 WT는 1씩 증가함 proc[j][2]++; } else if(j == sel_proc)//이는 프로세스에 CPU가 할당되어 실행이 완료된 특수한 경우 proc[j][3]++; } //Time_Chart 출력 if(i != 0) { if(sel_proc != time_chart[i - 1]) //CPU가 다른 프로세스에 할당된 경우 현재 시간 값과 새 프로세스의 이름을 프린트 { System.out.print("--" + i + "--P" + sel_proc); } } else//현재 시간이 0인 경우, 즉 인쇄가 막 시작되면 첫 번째 선택된 프로세스의 이름을 프린트 System.out.print(i + "--P" + sel_proc); if(i == total_time - 1)//모든 프로세스 이름이 인쇄되었으므로 실행이 끝나는 시간을 프린트 System.out.print("--" + (i + 1)); //다음 번 반복을 위해 sel_proc 값 업데이트 current_q++; if(current_q == q || proc[sel_proc][1] == 0)//시간이 만료되었거나 현재 프로세스가 실행이 완료된경우 { current_q = 0; //sel_proc에 대해 다음 유효한 값을 선택 for(int j = 1; j <= n; j++) { sel_proc++; if(sel_proc == (n + 1)) sel_proc = 1; if(proc[sel_proc][1] != 0) break; } } } System.out.println(); System.out.println(); //각 프로세스의 WT 및 TT 인쇄 System.out.println("P\t WT \t TT "); for(int i = 1; i <= n; i++) { System.out.printf("%d\t%3dms\t%3dms",i,proc[i][2],proc[i][3]); System.out.println(); } System.out.println(); //WT & TT 평균시간 인쇄 float WT = 0,TT = 0; for(int i = 1; i <= n; i++) { WT += proc[i][2]; TT += proc[i][3]; } WT /= n; TT /= n; System.out.println("The Average WT is: " + WT + "ms"); System.out.println("The Average TT is: " + TT + "ms"); } }


반응형

'프로그래밍 > Java' 카테고리의 다른 글

[JAVA] 리터럴과 형변환  (0) 2022.01.04
JAVA - 인스턴스, 힙 메모리  (1) 2022.01.01
반응형


◎ DB.properties 파일

▼ 내용

properties 의 파일에 가져올 key = 내용 ; 식으로 적어준다.

어차피 java에선 properties 에서 getproperty 로 읽어오기 때문이다.

driver=org.postgresql.Driver url=jdbc:postgresql://localhost:5432/postgres username=postgres password=goodday

◎ 외부 properties 읽기

▼ 내용

.jar 파일과 .properties의 같은 폴더 안에 잇을경우 파일 이름 DB.properties 만써주고

다른경로에 잇을경운 fileReader 안에 ../../ 같은 상대경로를 써주거나 절대경로를 써주면된다.

import java.io.*; import java.util.*; public class EntryMain { public static void main(String[] args) { FileReader resources= new FileReader("DB.properties"); Properties properties = new Properties(); try { properties.load(resources); System.out.println(properties.getProperty("driver")); System.out.println(properties.getProperty("username")); System.out.println(properties.getProperty("password")); System.out.println(properties.getProperty("url")); } catch (IOException e) { e.printStackTrace(); } } }

◎ 내부 properties 읽기

▼ 내용

내부 properties 에 잇을경운 아래 resource 변수에 패키지 구조와 파일명을 써주면된다

import java.io.IOException; import java.io.Reader; import java.util.Properties; public class EntryMain { public static void main(String[] args) { String resource = "config/DB.properties"; Properties properties = new Properties(); try { Reader reader = Resources.getResourceAsReader(resource); properties.load(reader); System.out.println(properties.getProperty("driver")); System.out.println(properties.getProperty("username")); System.out.println(properties.getProperty("password")); System.out.println(properties.getProperty("url")); } catch (IOException e) { e.printStackTrace(); } } }


반응형

+ Recent posts