본문 바로가기
Be Smart/JAVA

[Learn.JS] JavaScript-5 (Promises, Async and Await, 자바스크립트 객체)

by 반월하 2022. 1. 7.
728x90

Promises


Promises는 자바스크립트에서 비동기 프로그래밍의 기본이며 마스터하는 데 매우 중요하다.

What is Asynchronous Programming?


비동기식 프로그래밍 또는 줄여서 비동기식 프로그래밍은 코드의 다른 부분들이 즉시가 아닌 시간을 바꿔가며 실행될 수 있게 하는 프로그래밍 방법입니다.

이것은 원격 서버에서 정보를 가져와 서버가 반환한 내용으로 어떤 작업을 수행하는 코드를 작성하고자 할 때 주로 필요합니다.

function getServerStatus() {
		const result = fetch("/server/status");
		
		// THIS WILL NOT WORK!
		console.log("The status from the server is: ", result.ok);
}

파이썬과 같은 많은 프로그래밍 언어에서는 함수들이 기본적으로 동기 함수이기 때문에 이 매머드는 작동한다.

자바 스크립트에서 함수들이 무언가를 하기 위해 기다려야 하는 대부분의 API들은 기본적으로 비동기적이며, 이는 이 코드가 우리가 생각하는 것을 하지 않는다는 것을 의미한다. fetch 함수에서 반환되는 이 "thing"을 자바스크립트에서는 Promise라고 부른다.

위의 코드를 작동시키기 위해서는 다음과 같은 방식으로 함수를 작성해야 합니다.

function getServerStatue() {
		const result = fetch("/server/status");

		result.then(function(status) {
				console.log("The status from the server is: ", status.ok);
		}
}

여기서 우리는 Promise의 방법 중 하나인 then 함수를 사용했습니다.

The Promise Object


프로미스(Promise)는 두 가지 특성을 가진 네이티브 자바스크립트 객체이다.

  1. 이것은 함수인 단일 인수를 수신합니다. 이 함수에는 resolve 함수와 reject 함수의 두 개의 인수가 필요합니다. Promise 안에 적힌 코드는 이 두 기능 중 하나를 사용해야 합니다.
  2. then 메서드(및 다른 유사한 메서드)를 사용하거나 await 문을 사용할 때 기다릴 수 있습니다( async / await 문은 별도의 튜토리얼이 있습니다.)
  3. 비동기 함수는 함수에 의해 정의되며, 함수는 반환되어야 할 값을 반환하는 대신 Promise 객체를 반환하며, 이것은 결국 해결되고 사용자에게 답을 줄 것이다.

예를 들어, 두 숫자의 합을 계산하려고 하는데 값이 아닌 Promise 값을 반환하는 함수를 쓴다고 가정합시다.

function sumAsync(x, y) {
		const p = new Promise((resolve, reject) => {
				// this resolves the promise we just created with the ouput of x + y
				resolve(x + y);
		});

		// This returns the promise, not the value
		return p;
}

// let's use the function now
sumAsync(5,7).then((result) => {
		console.log("The result of the addition is:", result);
});

언제 이것이 매우 유용할 수 있을까요? 계산을 간접적으로 수행해야 하는 경우(예: 잠시 기다린 후 또는 fetch 명령을 사용하여 서버에서 정보를 검색하는 경우)

0.5초 후에만 설루션을 해결하도록 예를 수정하겠습니다.

function sumAsync(x, y) {
    console.log("1. sumAsync is executed");
    const p = new Promise((resolve, reject) => {
        // run this in 500ms from now
        setTimeout(() => {
            console.log("4. Resolving sumAsync's Promise with the result after 500ms");
            resolve(x + y);
        }, 500);

        // we don't need to return anything
        console.log("2. sumAsync Promise is initialized");            
    });
    console.log("3. sumAsync has returned the Promise");
    return p;
}

// let's use the function now
sumAsync(5, 7).then((result) => {
    console.log("5. The result of the addition is:", result);
});

Rejecting promises


동기적 흐름에서 사용자에게 무언가가 잘못되어 예외를 잡을 수 있음을 알려주고자 할 경우 throw인수를 사용하여 예외를 발생시킨다. 약속을 사용할 때, 우리는 대신 reject 함수를 작동시킬 필요가 있습니다.

같은 함수를 쓰려고 하는데, 값이 음수이면 거부를 한다고 가정합시다.

function sumAsync(x, y) {
		return new Promise((resolve, reject) => {
				// run this in 500ms from now
				setTimeout(() => {
						if (x < 0 || y < 0) {
								reject("Negative values received");
						} else {
								resolve( x + y );
						}
				}, 500);

				// we don't need to return anything
		});
}

sumAsync(-5, 7).then((result) => {
		console.log("The result of the addition is:", result);
}).cathch((error) => {
		console.log("Error received:", error);
});

Exercise

문자열을 수신하고 Promise를 반환하는 함수를 작성합니다.

약속은 문자열의 대문자 버전으로 확인되어야 하지만 문자열이 null이면 거부되어야 합니다.

function upperCaseAsync(s) {
    // write your code here
		return new Promise((resolve, reject) => {
				if ( s === null ) {
						reject("string is null");
				} else {
							resolve(s.toUpperCase());
				}
		});
}

upperCaseAsync("steve").then(console.log);
upperCaseAsync(null).catch((x) => {
    console.log("No string received!");
});

Async and Await

자바스크립트의 async 및 await 키워드는 coroutines이라는 것을 도입함으로써 비동기 프로그래밍을 쉽게 하기 위해 사용된다. coroutines 은 어떤 이벤트가 발생할 때까지 실행을 일시 중지하고 제어 권한을 메인 루프에 반환할 수 있는 함수이다. 이것은 쓰기, 이해, 유지관리가 더 쉬워지는 콜백 기능을 사용하기 위한 대안적 접근법이다.

The await keyword


await keyword는 Promise가 해결될 때까지 자바스크립트에 현재 함수의 실행을 중지한 다음 Promise의 값을 반환하도록 지시하는 특수 명령어이다. Promise가 해결되었는지 확인하고 해결된 약속의 값을 반환하는 끝없는 루프로 볼 수 있다.

await 키워드는 async 함수(앞에서 설명한 coroutine) 내에서만 작동합니다. async 함수에 대한 까다로운 점은 값 대신 Promise를 반환한다는 것입니다. 즉, async 함수를 실행해야 할 때마다 반환 값을 얻으려면 async 함수를 await 해야 합니다.

나중에 await를 사용하여 sumAsync를 구현할 수 있도록 Promise 튜토리얼에서 sumAsync의 예를 다시 살펴보겠습니다. The sleep 함수는 밀리초 후에 해결되는 Promise을 반환하고 setTimeout을 사용하여 작동합니다.

function sleep(ms) {
		return new Promise((resolve) => setTimeout(resolve, ms));
}

function sumAsync(x, y) {
		return new Promise((resolve, reject) => {
				sleep(500).then() => {
						resolve(x + y);
				});
		});
}

// let's use the function now
sumAsync(5, 7).then((result) => {
		console.log("The result of the addition is:", result);
});

우리는 sleep 함수에 await를 사용한 다음 결과를 반환함으로써 코드 sumAsync를 더 좋게 만들 수 있다.

function sleep(ms) {
		return new Promise((resolve) => setTimeout(resolve, ms));
}

async function sumAsync( x, y ) {
		// this code waits here for 500 milliseconds
		await sleep(500);
		// done waiting. let's calculate and return the value
		return x + y;
}

// sumAsync is an async function, which means it returns a Promise.
sumAsync(5, 7).then((result) => {
		console.log("The result of the addition is:", result);
});

sumAsync는 async함수이기 때문에 Promise를 명시적으로 반환하는 이전 예제처럼 암시적으로 Promise를 반환한다. 두 sumAsync 함수는 기능이 완전히 동일하지만 async 함수를 사용하여 정의된 함수는 훨씬 이해하기 쉽습니다!

Exercise

500밀리 초를 대기한 다음 지정된 문자열의 대문자 값을 반환하는 비동기 함수를 씁니다. 제공된 sleep 함수를 사용합니다.

function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

async function uppercaseString(s) {
    // your code goes here
		await sleep(500);
		return(s.toUpperCase());
}

uppercaseString("edward").then(console.log);

Object Oriented JavaScript

JavaScript는 함수를 클래스로 사용하여 new 키워드를 사용하여 객체를 만듭니다. 다음은 예입니다.

function Person(firstName, lastName) {
		// construct the object using the arguments
		this.firstName = firstName;
		this.lastName = lastName;

		// a method which returns the full name
		this.fullName = function() {
				return this.firstName + " " + this.lastName;
		}
}

var myPerson = new Person("John", "Smith");
console.log(myPerson.fullName());           // outputs "John Smith"

new 키워드를 사용하여 개체를 만드는 것은 다음 코드를 작성하는 것과 같습니다.

var myPerson = {
		firstName : "John",
		lastName : "Smith",
		fullName : function()
		{
				return this.firstName + " " + this.lastName;
		}
}

객체를 만드는 두 방법의 차이점은 첫 번째 메서드는 클래스를 사용하여 객체를 정의한 다음 new 키워드를 인스턴스화하며 두 번째 메소드는 즉시 객체의 인스턴스를 생성한다는 것이다.

Exercise

사람의 이름과 나이를 숫자로 받아들이는 Person 클래스를 만듭니다.

사용자 클래스에는 "name, age years old" 구문의 문자열을 반환하는 description 메서드가 있어야 합니다. 예를 들어, 만약 존이 19살이라면, 그의 물체에 대한 함수는 "존, 19살"로 돌아온다.

// TODO: create the Person class using a function
var Person = function(name, age){
    this.name=name;
    this.age=age;
    this.describe = function(){
        return this.name + ", " + this.age + " years old";
    }
}
var jack = new Person("Jack", 25);
var jill = new Person("Jill", 24);
console.log(jack.describe());
console.log(jill.describe());
728x90

댓글