이전에 쓴 글에 이어서 프로미스를 구현한 뒤 예제를 통해 동작을 확인해보겠습니다.

 

 

이전 포스트

https://ahat-li.tistory.com/24

 

프로미스 동작 분석하기(1)

자바스크립트 공부를 하다가 프로미스에 대해서 공부한 내용을 정리해볼까 한다. 프로미스가 내부에서 어떻게 동작하는지 프로미스를 간단하게 구현하고 예제를 통해 분석해보았다. 아래 코드

ahat-li.tistory.com

 

 

예제2)

new _Promise((res, rej) => {
     res(1);
})
.then((e) => {
     console.log("aa ", e);
     return e + 1
})
.then((e) => {
     console.log("bb ", e);
})

 

예제2는 예제1과 비슷하지만 프로미스 내부의 res 함수를 실행시키는 방법이 다릅니다.

예제 1은 setTimeout(() => { res(1)}, 3000); 이렇게 res 함수가 setTimeout 안에 들어있지만

예제 2에서는 res가 바로 실행되게 됩니다.

 

예제를 분석하여 어떤 방식으로 프로미스 동작이 이루어지는지 확인해보겠습니다.

우선 new 를 통해 첫번째 프로미스 객체가 생성됩니다.

그리하여 프로미스 생성자가 실행되는데 생성자 내부에서 인자로 받은 collback 함수 객체를 바로 실행합니다.

저 함수 객체는

(res, rej) => {

     res(1);

}

이런 객체인데 보시면 res 함수를 바로 실행시키고 있습니다.

res와 rej가 resolve, reject 함수과 연결되어 있기 때문에

res를 통해 첫번째 프로미스 객체의 resolve 함수가 바로 실행되게 됩니다.

 

resolve 메서드를 보면 프로미스 객체의 상태로 fulfilled로 변경하고있습니다.

프로미스1의 promiseResult에 res를 통해 전달된 1이라는 값이 들어갑니다

또한 프로미스1의 fulfilledFun 함수객체를 실행하게 되어있지만

프로미스1의 fulfilledFun가 undefined 이기 때문에 아무런 동작도 하지 않습니다.

프로미스 생성자의 모든 동작이 완료되었기 때문에 콜스택이 비워지게 됩니다.

 

 

이후 프로미스1의 메서드인 then이 실행됩니다.

예제1 에서는 then이 resolve보다 먼저 실행되었지만

예제2 에서는 then 보다 resolve가 먼저 실행되었다는 차이점이 있습니다.

 

그래서 then 메서드의 동작도 달라지는데요 프로미스1의 상태가 fulfilled이기 때문에 

return new _Promise(resolve =>   resolve(onFulfilled(this.promiseResult)));

이런 동작을 하게 됩니다.

 

 then의 메서드로 전달된 onFulfilled 함수 객체를 실행합니다.

then에 전달된 함수 객체는

(e) => {

     console.log("aa ", e);

     return e + 1

}

이런 모양을 하고 있습니다.

이 함수객체를 실행하기 때문에 aa 1 이라는 콘솔을 출력하고 2를 리턴하게 됩니다.

return new _Promise(resolve =>   resolve(2);

 

이제 then 메서드의 리턴값이 될 프로미스 객체를 생성하기 위해 

2번째 프로미스의 생성자를 실행하게 됩니다.

프로미스2의 상태값이 전달되고 프로미스2 생성자에 전달된 callback 함수객체를 바로 실행하게 됩니다.

프로미스2의 생성자에 전달된 callback 함수객체는

resolve =>   resolve(2) 이런 모양입니다.

callback 메서드를 바로 실행하기 때문에 프로미스2의 resolve 메서드가 실행되게 되는데 

여기서 프로미스2의 상태가 fulfilled로 바뀌고 promiseResult에는 2가 들어갑니다.

프로미스2의 fulfilledFun은 undefined 이기 때문에 아무런 동작도 하지 않습니다.

 

이후 프로미스2의 생성이 완료되고 콜스택은 다시 비워지게 됩니다.

 

 

 

다음은 프로미스2의 메서드인 then이 실행되게 됩니다.

전체적인 동작은 프로미스1의 then과 똑같습니다.

프로미스2의 상태가 fulfilled 인 상태에서 then 메서드가 실행되었기 때문에

then에 인자로 전달된 함수객체가 바로 실행되어 

bb 2 라는 콘솔 텍스트가 출력됩니다.

 

이후 프로미스3 객체가 생성되어 프로미스3의 생성자가 실행됩니다.

 

 

프로미스3의 생성자에 전달된 callback 함수에 의해서 프로미스3의 resolve 함수가 실행됩니다.

다만 프로미스3의 then 메서드가 실행되지 않기때문에 프로미스3의 생성자를 끝으로 예제2의 동작은 완료됩니다.

 

위에서 살펴본 내용을 요약하면 다음과 같이 볼 수 있을것 같습니다.

 

resolve 메서드가 then 메서드보다 먼저 실행될 경우

resolve 메서드가 실행된 시점에 프로미스 객체의 상태가 미리 fulfilled 상태로 변경되고

이후 then 메서드가 실행될 때 프로미스 객체의 상태가 fulfilled 일 때 인자로 들어온 함수 객체를 바로 실행시킴

이후 새로운 프로미스 객체를 생성하고 그 객체의 상태를 fulfilled 로 변경 후 리턴함

 

 

다만 자바스크립트 공식 프로미스에서도 저렇게 동작하는지는 나중에 제대로 확인을 해 보아야 할 것 같습니다...

 

이렇게 프로미스의 동작이 어떻게 이루어지는지 간단한 예제를 통해 알아보았는데

예제는 간단하지만 동작 자체는 상당히 복잡했습니다.

 

 

 

사실 위의 예제에서 사용하기 위해 구현한 프로미스 클래스에는 문제점이 있습니다.

프로미스 내부에서 저렇게  프로미스 객체를 생성하여 리턴하는 방식으로 

비동기 동작을 여러개 연결할 수 있습니다.

하지만 이번 예제를 위해 구현한 프로미스 클래스에서는 저런 방식의 동작이 불가능합니다...

 

이를 일부 함수동작을 바꾸는 것으로 동작하게 만들 수 있습니다.

다음 포스트에서는 일부 함수 내용을 수정하여 위와 같은 예제가 동작할 수 있도록 하겠습니다.

 

감사합니다.

자바스크립트 공부를 하다가 프로미스에 대해서 공부한 내용을 정리해볼까 한다.

프로미스가 내부에서 어떻게 동작하는지 프로미스를 간단하게 구현하고 예제를 통해 분석해보았다.

 

아래 코드는 프로미스를 간단히 구현한 코드이다.

const _Promise = class {
constructor(callBack) {
this.status = "pending";
this.promiseResult = undefined;
this.fulfilledFun = undefined;
this.rejectedFun = undefined;
callBack(
(v) => this.resolve(v),
(v) => this.reject(v));
}
_doTask(t) {
	 if (t !== undefined) {
	      setTimeout(t, 0);
	 }
}
resolve(v) {
if (this.status !== "pending") {
	return this;
}
this.status = "fulfilled";
this.promiseResult = v;
this._doTask(this.fulfilledFun)
}
then(onFulfilled) {
switch (this.status) {
case "pending": {
return new _Promise(resolve => {
       this.fulfilledFun = () => {resolve(onFulfilled(this.promiseResult))};
})
}
case "fulfilled": { return new _Promise(resolve => resolve(onFulfilled(this.promiseResult))); }
case "rejected": { break; }
}
return this;
} 

reject(err) {}
catch (onRejected) {}
}

 

아래 블로그를 참고하였습니다.

https://velog.io/@teihong93/Promise-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-1

 

Promise 구현하기 (1)

자바스크립트의 비동기 처리는 프로미스가 있기 전과 후로 나뉠 정도로, 프로미스라는 개념은 자바스크립트 진형에 많은 영향을 주었습니다.지금이야 async await 이라는 더 직관적이고 깔끔한 문

velog.io

 

인터넷을 찾아보니 프로미스를 구현한 예제는 많이 있는데 그 중에서 가장 간단한 예제를 골라 더 간단하게 만든 것이다.

다만 then과 catch 부분은 사용하는 상태만 다를 뿐이지 내부 구현 자체는 비슷하다.

그래서 코드를 더 간단하게 하기 위하여 catch 관련 부분은 코드를 제거한 뒤 분석해 보았다.

 

간단한 예제 2가지를 사용하여 내부에서 어떻게 동작하는지 살펴보았다.

 

예제 1)

new _Promise((res, rej) => {
     setTimeout(() => { res(1)}, 3000);
})
.then((e) => {
     console.log("aa ", e);
     return e + 1
})
.then((e) => {
     console.log("bb ", e);
})

간단한 프로미스 예제이다.

딱봐도 3초 후에 aa 1이 출력되고

그 후 bb 2가 출력될 것이라고 예상할 수 있다.

 

 

예제 분석

예제1이 실행되면 우선 첫번째 프로미스 객체를 생성한다.

그로 인해서 프로미스1의 생성자가 실행되게 된다.

생성자 함수가 실행되면 해당 프로미스 객체의 상태는 pending 상태가 된다.

생성자 함수를 보면 인자로 받은 콜백이라는 이름의 함수객체를 실행시키는데

이로 인해서 res와 rej가 프로미스1의 resolve, reject와 연결되게 된다.

이후 함수객체로 전달된 setTimeout(() => { res(1)}, 3000); 명령 또한 실행되게 된다.

setTimeout 함수는 실행되면 Web API 영역으로 이동하여 3초동안 대기하게 된다.

프로미스1 객체가 생성되었고 그 다음은 프로미스 1의 메서드인 then 이 실행된다.

then 메서드에서는 프로미스 객체를 새로 생성하여 리턴하는 동작을 한다.

프로미스2 객체의 생성자가 실행되며 이때 전달된 함수 객체를 보면

화살표 함수로 이루어져 있고 this.fulfilledFun 라는 부분이 있다.

 

화살표 함수에서 this는 자신을 실행시킨 외부객체의 this를 가리키게 되므로 여기에서의 this는 프로미스1이 된다.

즉 프로미스1의 fulfilledFun 에 () => {resolve(onFulfilled(this.promiseResult))} 라는 값을 넣게 된다.

resolve에는 this가 붙지 않았으니 프로미스2의 resolve가 되고 onFulfilled 부분은 then 메서드에 전달된 함수객체가 된다.

그리고 나서 두번째 then이 실행되는데 두번째 첫번째 then 에서 프로미스2 객체가 리턴되었으니 프로미스2의 then 메서드가 된다.

이전 동작과 똑같이 프로미스 3 객체가 생성되고 프로미스2의 fulfilledFun에 값이 들어가게 된다.

 

 

이후에는 특별한 동작이 없다가 Web APIs에 들어간 setTimeout 함수가 완료되어 내부의 res 함수가 실행되게 된다.

 

 

이후 프로미스1의 resolve 메서드가 실행되게 되는데

진행되면서 프로미스 1의 상태가 fulfilled 상태로 변한다.

보면 프로미스1의 fulfilledFun 값을 setTimeout 에 감싸 실행한다.

fulfilledFun 함수를 setTimeout 으로 실행하는 이유는 프로미스는 자신이 실행하는 함수를

마이크로 태스크큐에 넣어 실행하지만 그 부분은 따라할 수가 없으니 비슷하게 태스크큐에 넣어서 실행하기 위함이다.

Web APIs 에 전달된 함수는 태스크큐로 전달된다.

 

그리하여 

() => {resolve(onFulfilled(this.promiseResult))} 이런 함수가 실행되게 되는데

우선 onFulfilled(this.promiseResult) 이 부분부터 콜스택에 들어가게 된다.

onFulfilled 라는건 아까전에 첫번째 then에 전달된 함수객체인데

구체적으로는 

(e) => {

     console.log("aa ", e);

     return e + 1

}

이거다.

여기서 e는 프로미스1 객체의 promiseResult이므로 1이 된다.

그렇게 aa 1 이라는 콘솔 텍스트를 출력하고

2를 리턴한다.

 

이후 2가 리턴되었기 때문에 

() => {resolve(2)} 

이런 함수가 콜스택에 들어가게 된다.

여기에서 resolve는 프로미스2의 resolve가 되는데 

resolve 함수를 보면 아까와 마찬가지로 자신의 fulfilledFun 을 setTimeout에 넣고 실행한다.

 

프로미스2의 fulfilledFun은 

(e) => {

     console.log(bb ", e);

}

가 되고 e는 2이기 때문에 

bb 2 라는 콘솔 텍스트를 출력하게 된다.

 

 

이후 프로미스3의 resolve 함수도 실행하지만 

프로미스3은 fulfilledFun 값이 undefined 이므로 아무것도 실행하지 않는다.

 

이렇게 

aa 1

bb 2

라는 텍스트를 출력하는것으로 프로미스 예제 1번이 완료되었다.

 

 

 

 

예제 1을 사용하여 프로미스를 분석해 보았는데

여기서는 프로미스의 then 메서드가 resolve 메서드보다 먼저 실행된 것을 알 수 있다.

프로미스 객체에 then 메서드의 인자로 들어온 함수객체를 등록시키고

resolve 메서드가 실행되면 등록시켜놓은 함수객체를 실행시키는 방식이라고 요약할 수 있을것 같다.

 

이와 다르게 예제2는 resolve 메서드가 then 메서드보다 먼저 실행되므로 

동작방식이 조금 달라진다.

예전에 핸드폰에 용량이 너무 부족해서

클라우드 스토리지를 이것저것 알아본적이 있었다.

 

네이버 클라우드, 구글 클라우드, 원드라이브 다 알아보았는데 내 마음에 드는것은 없었다.

굳이 꼽자면 네이버 클라우드쪽이 가장 쓰기 좋았지만

안그래도 돈 나가는것도 많은데 매달 돈을 쓰면서까지 사용해야할 정도는 아니기도 하고...

 

그래서 무료 오픈소스 클라우드 서버프로그램인 파이디오(Pydio) 등도 설치하고 다 해보았지만

생각보다 무겁고 내 빈약한 스마트폰 환경에서는 사용하기가 어려웠다.

 

그러다가 이미지 전용 클라우드 서버같은건 없을까 싶어서 찾아보다가  그냥 내가 만들기로 했다.

내가 진짜로 원하는 기능은 정말 간단했는데

 

그냥 이미지파일을 업로드 다운로드가 가능하고 

목록의 이미지는 썸네일을 표시 해서 표시하는데 필요한 용량은 줄이고

이미지 썸네일을 누르면 원본 이미지를 표시해서 양옆 스와이프로 다음 이전 이미지로 이동할 수 있는 정도?

 

이정도만 있으면 딱 좋겠다고 생각했다.

 

일단 모바일에서 사용이 가능해야되는데 앱으로 만들기는 어려우니까

간단하게 html과 자바스크립트 그리고 golang을 사용해서 만들었다.

 

일단 제작 컨셉은 다른 오픈소스 클라우드 프로그램들을 사용하다보니

설치나 사용방법 복잡하다는 것을 느껴서

다운받고 실행파일만 눌러서 딱 실행만 하면 바로 쉽게 사용할 수 있는 프로그램이다.

 

프로그램 외형은 컨셉이 아니라 그냥 내가 디자인 센스가 없어서 저렇게 됐다.

 

github.com/AhatLi/ahat-simple-image-gallery

 

AhatLi/ahat-simple-image-gallery

A very simple image gallery server developed with go. Suitable for use on mobile. - AhatLi/ahat-simple-image-gallery

github.com

서버 프로그램을 실행시킨 후 브라우저로 서버의 주소에 접속하고

로그인을 하면 위와같은 화면이 나온다.

 

로그인 기능은 처음에는 만들 생각이 없었는데

서버 로그를 살펴보던 중에 자꾸 이상한 IP에 요청이 계속 들어와서

그냥 로그인 기능을 추가해주었다.

 

사용하면서 또 필요하다고 느낀 기능으로는 

인증서를 이용한 SSL 기능과 이미지 업로드 기능

그리고 새폴더 같은거 만드는기능?

 

버그도 좀 있는것 같은데 그것도 확인해봐야겠다.

 

 

###Ahat Simple Gallary

```
모바일에서 사용하기 적합한 간단한 이미지 갤러리 서버입니다.

Ahat Simple Gallary를 실행시키고 
모바일 웹브라우저 혹은 데스크탑 웹 브라우저로 접속하여
이미지 갤러리 기능을 사용할 수 있습니다.
현재까지 구현된 기능은 아래와 같습니다.
```

```
 - 이미지를 썸네일화 하여 갤러리 목록에 표시
 - 썸네일을 클릭할 경우 원본 이미지를 표시
 - 이미지를 좌 우로 드래그하여 이전/다음 이미지 표시
 - 이미지를 선택 후 이미지 경로 이동 기능
 - 이미지를 선택 후 이미지 삭제 기능
 - 페이지 접속 시 로그인을 하여야 접속 가능
 - 이미지의 이름/크기/날짜별 정렬 기능
```

```
컴파일 방법
 go get github.com/disintegration/imaging
 go get gopkg.in/ini.v1
 go get github.com/gorilla/securecookie
 go build .\ImageCloud.go .\Utils.go .\login.go
```

```
사용방법 1. 윈도우 환경
1) images 파일에 이용한 이미지 파일을 구성한다.
2) ImageCloud.exe 파일을 실행한다.
2-1) 로그파일을 남기고 싶을 경우 CMD 창을 열고 바이너리 위치로 이동해 
     ` ImageCloud.exe >> ImageCloud.log ` 
     형식으로 실행한다.
3) 프로그램이 실행된 후 모바일 브라우저 혹은 브라우저로 접속하여 사용한다.
ex) http://127.0.0.1:9090/
```

 

 

아직 개선할 점이 많이 있지만

내 서버컴퓨터에 이미지를 넣어두고 외부에서 접속해서 보거나 가져가는 등의 작업은 가능하다.

 

나중에 기능을 추가해야겠다.

+ Recent posts