isMounted
๋ ์ด๋ฏธ ES6 ํด๋์ค์์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ ์ด๋ฏธ "์ ๊ฑฐํ ์ ์์ต๋๋ค"๋ผ๋ ๊ฒฝ๊ณ ๊ฐ ์์ง๋ง ์ค์ ๋ก ์ฌ์ฉํ์ง ์๋ github ๋ฌธ์ ๋ ์์ต๋๋ค. ์ค๋ ๋
ผ์์ ๋ฐ๋ฅด๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก isMounted
์์ ๋ฉ์ด์ง๊ธฐ ์์ํ๊ณ ๋ ์ด์ ์ฌ์ฉํ์ง ์๋๋ค๋ ๋ฐ ๋์ํ์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ฌ์ ํ ํ๋ผ๋ฏธ์ค(๋ฐ ๊ด๋ จ ์ฌ์ฉ ์ฌ๋ก)์ ๋ํ ๋ช ๊ฐ์ง ์ข์ ์ด์ผ๊ธฐ๋ฅผ ํ์
ํด์ผ ํฉ๋๋ค.
์ด ๋ฌธ์ ๋ ํด๋น ๋ชฉํ๋ฅผ ํฅํ ์งํ ์ํฉ์ ์ถ์ ํ๋ ๊ฒ์ ๋๋ค.
๋ฐฐ๊ฒฝ์ ๋ค์์ ์ฐธ์กฐํ์ญ์์ค.
๋๋ ์ด๊ฒ์ ๋์ํ์ง ์๋๋ค. ํนํ ES6 ์ฝ์์ componentWillUnmount
์์ ์์ ์ ์ผ๋ก ์ทจ์๋ ์ ์์ผ๋ฏ๋ก setState ๋๋ ๋ค๋ฅธ ์์
์ ์ ๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ๋์๋์ง ํ์ธํ๋ ์ ์ผํ ๋ฐฉ๋ฒ์ ์ ๊ฑฐํ๋ฉด ์ถ์ ํ๊ธฐ ์ด๋ ค์ด ๋น๋๊ธฐ ๋ฒ๊ทธ๊ฐ ๋ง์ด ๋ฐ์ํฉ๋๋ค.
@yaycmyk ๋ฐ๋ผ์ ๋ผ์ธ:
์ฐ๋ฆฌ๋ ์ฌ์ ํ ํ๋ผ๋ฏธ์ค(๋ฐ ๊ด๋ จ ์ฌ์ฉ ์ฌ๋ก)์ ๋ํ ๋ช ๊ฐ์ง ์ข์ ์ด์ผ๊ธฐ๋ฅผ ํ์ ํด์ผ ํฉ๋๋ค.
ํนํ ๋ด๊ฐ ๋์ดํ ๋ฐฐ๊ฒฝ ๋ฌธ์ ๋ฅผ ์ฝ์ผ์ญ์์ค. https://github.com/facebook/react/issues/2787#issuecomment -68738793
๋๊ธ ์ ์ฝ์์ต๋๋ค. ๋๋ ๋จ์ง ๋ฌธ์ ๋ฅผ ๋ค๋ฃจ๊ธฐ ์ด๋ ต๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ ์ฝ์์ ์ทจ์ํ ์ ์์ต๋๊น? ๋ชจ๋ ์ถ์ฒ/์ฆ๋ช /์์?
2015๋ 11์ 16์ผ ์์์ผ์ Evan Jacobs [email protected] ์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
๋๋ ์ด๊ฒ์ ๋์ํ์ง ์๋๋ค. ํนํ ES6 ์ฝ์์ ์ ๋ขฐํ ์ ์์ต๋๋ค.
componentWillUnmount์์ ์ทจ์๋์์ผ๋ฏ๋ก ํ์ธํ๋ ์ ์ผํ ๋ฐฉ๋ฒ์ ์ ๊ฑฐํฉ๋๋ค.
๊ตฌ์ฑ ์์๋ setState ๋๋ ๋ค๋ฅธ ์์ ์ด ์ด๊ธฐ ์ ์ ๋ง์ดํธ๋ฉ๋๋ค.
๋ง์ ๋น๋๊ธฐ ๋ฒ๊ทธ๋ฅผ ์ถ์ ํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ๋๋ค.
@nvartolomei ES6 Promise ์ฌ์์ ์ดํด๋ณด์ธ์.
์ด๊ฒ์ ๋น์ฅ์ ์ผ์ด๋๋ ๊ฒ์ด ์๋๋ผ ์ฅ๊ธฐ์ ์ธ ๋ชฉํ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ฐ๋ฆฌ๋ ๊ณํ๊ณผ ๋ ผ์๋ฅผ ํ ๊ณณ์์ ์ถ์ ํ๊ณ ๋ชจ๋ ๋ฌธ์ ์ ๋ํ ์๊ฒฌ์ ๊ณต์ ํ์ง ์๊ธฐ๋ฅผ ์ํฉ๋๋ค. ์ฐ๋ฆฌ๋ ํ์ฌ ์ทจ์ํ ์ ์๋ Promise์ ๋ฌธ์ ๋ฅผ ์๊ณ ์์ต๋๋ค. ์ด๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ์์ง ์ด๊ฒ์ ํ์ง ์์ ์ฃผ๋ ์ด์ ์ ๋๋ค.
@yaycmyk ๋งค์ฐ ๋ณต์กํ ๋ฌธ์ ๋ฅผ ๊ณผ๋ํ๊ฒ ๋จ์ํํ๊ธฐ ์ํด ... ์๊ฒฌ์ ๋ฐ๋ฅด๋ฉด ... ๋ง์ดํธ๋์ง ์์ ๊ตฌ์ฑ ์์์ ๋ํด setState
๋ฅผ ํผํ๊ธฐ ์ํด isMounted
๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ค์ ๋ก setState
๊ฒฝ๊ณ ๋ ํ์ํ๋ ค๊ณ ํ์ต๋๋ค. ์ค์ ๋ก๋ ๋ฌธ์ ๋ฅผ ์จ๊ธธ ๋ฟ์
๋๋ค. ๋ํ Promise์ ๊ฒฐ๊ณผ๋ก setState
๋ฅผ ํธ์ถํ๋ ๊ฒ์ ํ
์คํธ์์ ๋ฐ๋์ ๋ํ๋์ง ์๋ ๊ฒฝ์ ์กฐ๊ฑด์ ์ ๋ฐํ ์ ์๊ธฐ ๋๋ฌธ์ ์ด์จ๋ ์ฝ๊ฐ์ ์ํฐ ํจํด์
๋๋ค. ๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ ๊ทธ๊ฒ์ ์์ ๊ณ React์์ promise๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ "๋ชจ๋ฒ ์ฌ๋ก" ๊ถ์ฅ ์ฌํญ์ ํ์
ํ๊ณ ์ถ์ต๋๋ค.
๋ฌธ์ ๊ฐ ์ดํดํ๊ธฐ ์ด๋ ต๋ค๋ ๋ฐ๋ ๋์ํ์ง๋ง, ์ด๋ ์ฐ๋ฆฌ๊ฐ ์์ง ํ์ ํ๊ณ ์๊ณ ์์ง ๋ฏธ๋ฆฌ ์ค๋น๋ ๋ต๋ณ์ด ์๋ ๋ณต์กํ ๋ฌธ์ ์ด๊ธฐ ๋๋ฌธ์ ๋๋ค.
Promise์ ๊ฒฐ๊ณผ๋ก setState๋ฅผ ํธ์ถํ๋ ๊ฒ์ ์ด์จ๋ ์ฝ๊ฐ์ ์ํฐ ํจํด์ ๋๋ค. ํ ์คํธ์์ ๋ฐ๋์ ๋ํ๋์ง ์์ ๊ฒฝ์ ์กฐ๊ฑด์ ์ ๋ฐํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ฐ๋ฆฌ๋ ์ด์ ๋์ํ์ง ์์ ์ ์์ต๋๋ค. ์ฝํ ์ธ ๋ฅผ ๋น๋๊ธฐ์์ผ๋ก ๊ฐ์ ธ์ค๋ ๊ฒฝ์ฐ๊ฐ ์๊ณ ํด๊ฒฐ๋๋ฉด ํด๋น ์ฝํ ์ธ ๋ฅผ ํ์ ํ๊ธฐ ์ํด ์ ์ฒด ๊ท๋ชจ์ ์ฌ๋ ๋๋ง์ ๊ฑฐ์น๊ณ ์ถ์ง ์์ ๋๊ฐ ์์ต๋๋ค. ์ ์ฒด ๊ฐ์ ๋ ๋๊ฐ ํ์ํ์ง ์์ ๋ฌดํ ํ ์ด๋ธ ๋ทฐ ๊ตฌํ์์ ํนํ ์ฌ์ฉํฉ๋๋ค.
์ฝ์์ ์ทจ์ํ ์ ์์ ์๋ ์์ง๋ง ๋ค์๊ณผ ๊ฐ์ด ๋ง์ดํธ ํด์ ์ ๊ตฌ์ฑ ์์๋ฅผ ์ญ์ฐธ์กฐํ๋๋ก ํ ์ ์์ต๋๋ค.
const SomeComponent = React.createClass({
componentDidMount() {
this.protect = protectFromUnmount();
ajax(/* */).then(
this.protect( // <-- barrier between the promise and the component
response => {this.setState({thing: response.thing});}
)
);
},
componentWillUnmount() {
this.protect.unmount();
},
});
์ค์ํ ์ฐจ์ด์ ์ this.protect.unmount()
๊ฐ componentWillUnmount
์์ ํธ์ถ๋ ๋ ๋ชจ๋ ์ฝ๋ฐฑ์ด ์ญ์ฐธ์กฐ๋๋ค๋ ๊ฒ์
๋๋ค. ์ฆ, ๊ตฌ์ฑ ์์๊ฐ ์ญ์ฐธ์กฐ๋๊ณ ํ๋ผ๋ฏธ์ค๊ฐ ์๋ฃ๋๋ฉด no-op์ ํธ์ถํฉ๋๋ค. ์ด๊ฒ์ ์ฝ์์ด ๋ง์ดํธ๋์ง ์์ ๊ตฌ์ฑ ์์๋ฅผ ์ฐธ์กฐํ๋ ๊ฒ๊ณผ ๊ด๋ จ๋ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํด์ผ ํฉ๋๋ค. ProtectFromUnmount ์์ค
์ด ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ๋ชจ๋ ์ฝ์์ ์ทจ์๋ฅผ ์ถ๊ฐํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then((val) =>
hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
);
promise.catch((error) =>
hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
ํธ์ง: ์ ํ์ฑ/์์ ์ฑ์ ์ํด ์ ๋ฐ์ดํธ๋์์ต๋๋ค.
์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
const somePromise = new Promise(r => setTimeout(r, 1000));
const cancelable = makeCancelable(somePromise);
cancelable
.promise
.then(() => console.log('resolved'))
.catch(({isCanceled, ...error}) => console.log('isCanceled', isCanceled));
// Cancel promise
cancelable.cancel();
ES6 ์ฝ์์ ์ทจ์ํ ์ ์๋๋ก ์ง์ํ๋ ๋ฐฉ๋ฒ์ ๋์ดํ๋ ๊ฒ์ ์์ ์ด ์๋๋๋ค. ๊ทธ ์๋๋ ์ฌ์ ์ฃผ๋ณ์์ ์๋ํ๋ ค๊ณ ํ๊ธฐ ๋ณด๋ค๋ ์ฌ์๊ณผ ํจ๊ป ์๋ํ๋ ์๋ฃจ์ ์ ์ ๊ณตํ๋ ๊ฒ์ด์ด์ผ ํฉ๋๋ค.
๋๋ ๋์ํ๋ค. ํ๋ผ๋ฏธ์ค ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์์ ๋ ์ปดํฌ๋ํธ๊ฐ ์ฌ์ ํ ๋ง์ดํธ๋์ด ์๋์ง ๋จ์ํ ํ์ธํ๋ ๋์ ๋ชจ๋ ์ข
๋ฅ์ ๋ง๋ฒ์ ์์กดํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ์ค์ ํด์ผ ํ๋ ์ปดํฌ๋ํธ์์ ํ๋ผ๋ฏธ์ค๋ฅผ "์ธ๋ฐ์ธ๋"ํ ์ ์์ด์ผ ํฉ๋๋ค. ์ค๊ณ๋์์ต๋๋ค.
๋์๊ฒ ๊ทธ๊ฒ์ ๊ฐ๋จํ ํ
์คํธ๊ฐ ์ด๊ฒ์ ์ฒ๋ฆฌํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ธ ์๋ฃจ์
์ ๊ณผ๋ํ๊ฒ ์์ง๋์ด๋งํ๋ ๊ฒ์ฒ๋ผ ๋๊ปด์ง๋๋ค.
๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ๋จํ ๊ฒ์ฌ๋ฅผ ๊ณ์ํ ์ ์์ต๋๋ค.
React.createClass(function() {
componentDidMount: function() {
this._isMounted = true;
ajax(/* */).then(this.handleResponse);
}
handleResponse: function(response) {
if (!this._isMounted) return; // Protection
/* */
}
componentWillUnmount: function() {
this._isMounted = false;
}
});
์ด๊ฒ์ ๋ฌผ๋ก ๋ด ์๊ฒฌ์ด์ง๋ง ๋ฐ์ ๊ตฌ์ฑ ์์ ๋ด๋ถ์ ์ฝ์์ด ์๋ ๋น๋๊ธฐ ๋ฐ์ดํฐ ๋ก๋๋ ์ฐ๋ฆฌ ๊ณ ์ ์ ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋์ ๋ฐ์์ผ๋ก ๋ค๋ฃจ์ด์ผ ํ๋ ์ผ๋ฐ์ ์ธ ์๋๋ฆฌ์ค์ธ ๊ฒ ๊ฐ์ต๋๋ค.
๋ฌธ์ ๋ ์ค์ ๋ง์ดํธ ์ํ๋ฅผ ๋ฐ๋ฅด๊ธฐ ์ํด ๋ฐ์์ด ๊ฐ ๊ตฌ์ฑ ์์(์ ์๋ ๊ฒฝ์ฐ componentDidMount๋ฅผ ์ฐ๊ฒฐํ๋ ๊ฒ๊ณผ ๋์ผ)์์ DOM ๋ง์ดํธ ํ๋ก์ธ์ค๋ฅผ ์๋ฃํ ๋ ๋ฆฌ์ค๋๋ฅผ ์ถ๊ฐํด์ผ ํ์ง๋ง ํ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. ์ฌ๊ธฐ์ ๊ธฐ ๋๋๋ ๊ฒ. componentDidMount๊ฐ ์ ์๋์ง ์์์ผ๋ฏ๋ก ๊ตฌ์ฑ ์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก DOM ๋ง์ดํธ ์ค๋น๋ฅผ ์์ ํ์ง ์์ต๋๋ค.
setState
๊ฐ ์ํ๋ ์ํ ๋ณ๊ฒฝ์ผ๋ก ํด๊ฒฐ๋๋ ์ฐ๊ฒฐ๋ ์ฝ์์ ์ ๋ฌํ ์ ์๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ๋๋ฉด ๋ณด๋ฅ ์ค์ธ ์ฝ์์ด ์์ผ๋ฉด ์ต์ข
๊ฒฐ๊ณผ๊ฐ ๋ฌด์๋ฉ๋๋ค.
@istarkov ๋ฉ์ง ํจํด, ์ข์์! ๋ค์์ ์ฝ๊ฐ ๋ณ๊ฒฝ๋ API์ ๋๋ค.
// create a new promise
const [response, cancel] = await cancelable(fetch('/api/data'));
// cancel it
cancel();
๋๋ React์ ์ต์ํ์ง ์๊ณ ๋ฌธ์๋ฅผ ์ฝ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋์ง๊ธฐ ์ํด : Load Initial Data via Ajax ํ์ .isMounted()
๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ์น ์ฌ์ดํธ๊ฐ ์น ์ฌ์ดํธ์ ๋์ํ์ง ์์ต๋๋ค. ์์ @istarkov ํจํด์ ์ฌ์ฉํ์ฌ componentWillUnmount
์์ ์ด๊ธฐ ๋ก๋๋ฅผ ์ทจ์ํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์ ํ ํ์ ๋ณด๋ ๊ฒ์ด ์ข์ต๋๋ค.
@dtertman https://github.com/facebook/react/pull/5870 ์์ ์์ ๋์์ผ๋ฉฐ ๋ฌธ์๊ฐ ์ ํ๋๋ฉด ์จ๋ผ์ธ ์ํ๊ฐ ๋ฉ๋๋ค.
@jimfb ๊ฐ์ฌํฉ๋๋ค. ๊ฒ์์์ ์ด๋ป๊ฒ ๋์ณค๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
@istarkov ๋ ์ด๊ฒ์ด ์๋์ ์ธ ๊ฒ์ธ์ง ํ์คํ์ง ์์ง๋ง ์๋ ์ฝ์์ด ์คํจํ๋ฉด makeCancelable
๊ฐ ์ฒ๋ฆฌ๋์ง ์์ต๋๋ค. ์๋ ์ฝ์์ด ๊ฑฐ๋ถ๋๋ฉด ์ฒ๋ฆฌ๊ธฐ๊ฐ ํธ์ถ๋์ง ์์ต๋๋ค.
์๋ ์ฝ์์ ๋ํ ์ค๋ฅ๋ฅผ ๊ณ์ ์ฒ๋ฆฌํ๊ธฐ๋ฅผ ์ํ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ์ด์์ ์ด์ง ์์ ๊ฒ ๊ฐ์ต๋๋ค.
๋ค์์ ์๋ ์ฝ์์์ ๊ฑฐ๋ถ๋ฅผ ์ฒ๋ฆฌํ๋ makeCancelable
๋ํ ์ ์ ์์
๋๋ค.
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then((val) =>
hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
);
promise.catch((error) =>
hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
์ทจ์ ๊ฐ๋ฅํ ์ฝ์์ ๋ง๋๋ ๊ฒ์ด ์ข์ ์๊ฐ์ธ์ง ํ์ ํ ์ ์์ง๋ง ์ฝ์์ ์ทจ์ํ ์ ์๋๋ก ๋ง๋ค๋ ค๋ฉด ๊ธฐ๋ณธ ๋์์ ์ ์งํด์ผ ํฉ๋๋ค. :)
@vpontis : +1:
@istarkov ๊ทํ์ ์๋ ๊ฒ์๋ฌผ์ ์ฌ๊ธฐ์์ ์ฐธ์กฐ๋ฉ๋๋ค: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
๊ฒ์๋ฌผ์ ์ ๋ฐ์ดํธํ๊ณ ์ถ์ต๋๊น ์๋๋ฉด ๊ฒ์๋ฌผ ์์ฑ์์๊ฒ ๋ฉ์์ง๋ฅผ ๋ณด๋ด์ผ ํฉ๋๊น?
@vpontis ๊ฐ์ฌํฉ๋๋ค, ์์ ํ๊ฒ ์ต๋๋ค! (https://github.com/facebook/react/pull/6152)
์๋ ํ์ธ์ @jimfb , ์ธํฐ๋ท์์ ๋น์ ์
makeCancelable
ํจ์์ ๋ ๋ค๋ฅธ ๋ฒ๊ทธ ์์ : ์ต๊ทผ ๋
ธ๋ ๋ฒ์ ์์ UnhandledPromiseRejectionWarning
๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค(ํนํ ์ ๋ฒ์ ์ ๋
ธ๋๋ก ํ
์คํธ๋ฅผ ์คํํ ๋). ๋
ธ๋ 6.6.0 ์ ๋ณ๊ฒฝ ์ฌํญ ์ค ํ๋๋ ์ฒ๋ฆฌ๋์ง ์์ ๋ชจ๋ ์ฝ์์ด ๊ฑฐ๋ถ๋๋ฉด ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ๋ค๋ ๊ฒ์
๋๋ค. @vpontis ์ ๊ธฐ์กด ์ฝ๋์๋ ๋์ผํ ๊ธฐ๋ณธ ์ฝ์์ ๋ํด ๋ณ๋์ then
๋ฐ catch
ํธ์ถ์ด ์์์ต๋๋ค. ํจ๊ณผ์ ์ผ๋ก, ์ด๊ฒ์ ์ฑ๊ณต๋ง ์ฒ๋ฆฌํ๋ ์ฝ์๊ณผ ์ค๋ฅ๋ง ์ฒ๋ฆฌํ๋ ์ฝ์์ _2_ ์์ฑํฉ๋๋ค. ์ฆ, ์ค๋ฅ๊ฐ ์๋ ๊ฒฝ์ฐ ์ฒซ ๋ฒ์งธ ์ฝ์์ด ๋
ธ๋์์ ์ฒ๋ฆฌ๋์ง ์์ ์ฝ์ ๊ฑฐ๋ถ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ ์ ๋งค์ฐ ์ฝ์ต๋๋ค. ์ฑ๊ณต ๋ฐ ์ค๋ฅ ํธ๋ค๋ฌ ๋ชจ๋์ ๋ํด ํ๋์ ์ฝ์์ ํ๋๋ก ๋ ํธ์ถ์ ์ฐ๊ฒฐํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ๋ค์์ ๊ณ ์ ์ฝ๋์ ๋๋ค.
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise
.then((val) =>
hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
)
.catch((error) =>
hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
@alangpierce ์ ๋ต ์ ๋งค์ฐ ๊ฐ๊น์ง๋ง ์ ํํ์ง๋ ์์ต๋๋ค. resolve()
๋๋ reject()
๊ฐ ํด๊ฒฐ๋ ํ๋ผ๋ฏธ์ค์ ๋ํด ์ด๋ค ์ด์ ๋ก๋ ๋๊ธฐ์ ์ผ๋ก throwํ๋ฉด ๋ ํธ๋ค๋ฌ๊ฐ ๋ชจ๋ ํธ์ถ๋ฉ๋๋ค.
ํด๊ฒฐ์ฑ
์ .then(onFulfilled, onRejected)
ํจํด์ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค.
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
(val) => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
(error) => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
์ด makeCancelable ์๋ฃจ์ ์ isMounted()๊ฐ ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋ ์ด์ ์ ๋ํด ํฌ์ธํธ 3์ ๋ณผ ๋ isMounted() ํธ์ถ๊ณผ ํจ๊ณผ์ ์ผ๋ก ๋์ผํ์ง ์์ต๋๊น?
๊ตฌ์ฑ ์์๊ฐ ์์ ํ ๋ง์ดํธ ํด์ ๋๋ฉด setState๋ฅผ ํธ์ถํฉ๋๋ค.
์ด๊ฒ์ ๋น๋๊ธฐ ์ฝ๋ฐฑ์ด ์ ๋๋ก ์ ๋ฆฌ๋์ง ์๋๋ค๋ ๊ฐ๋ ฅํ ํ์์ ๋๋ค. ๋ถํํ๋, ์ฃผ๋ฅ JS API๋ฅผ ์ฌ์ฉํ๋ฉด ๋งค๋ฌ๋ฆฐ ๋น๋๊ธฐ ์ฝ๋ฐฑ์ ์ ๋ฆฌํ๋ ๊ฒ์ ๋งค์ฐ ์ฝ๊ฒ ํผํ ์ ์์ต๋๋ค.
ํ๋์ ์ฝ๋ฐฑ์ ํฐ ๋ฌธ์ ๊ฐ ์๋๋๋ค. ๊ทธ๋ฌ๋ ํด๋น ์ฝ๋ฐฑ์ ๊ฐ์ฒด ๋ฐ ์ค๊ฐ ์ฝ๋ฐฑ, ์ฝ์ ๋ฐ ๊ตฌ๋ ์ ๊ณ์ ๊ฑธ๋ฆฝ๋๋ค. ๋ง์ ๊ตฌ์ฑ ์์๊ฐ ์ด ์์ ์ ์ํํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ๊ฐ ๋น ๋ฅด๊ฒ ๋ฐ์ํฉ๋๋ค.
makeCancellable์ ๊ตฌ์ฑ ์์์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ณด์ ํ๋ ํจ์์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ณด์ ํ๊ฒ ๋๋ ๋ ๋ค๋ฅธ ์ฝ์์ ์์ฑํฉ๋๋ค. makeCancellable ์๋ฃจ์ ์ ๋ถ์ธ ์์ฑ isMounted๋ฅผ ์ฝ์์ผ๋ก ์ฎ๊ธฐ๋ ๊ฒ์ ๋๋ค.
GC ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด cancel()์ด ํธ์ถ๋ ๋ null์ ์ ๊ฑฐํด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ฌ์ ํ ๋น๋๊ธฐ ํ๋ก์ธ์ค์์ ๊ตฌ์ฑ ์์๋ก์ ์ฐธ์กฐ ์ฒด์ธ์ด ์์ต๋๋ค.
class CancellableDeferred {
constructor(request) {
this.deferred = $.Deferred();
request.then((data) => {
if (this.deferred != null) {
this.deferred.resolve(data);
}
});
request.fail((data) => {
if (this.deferred != null) {
this.deferred.reject(data);
}
});
}
cancel() {
this.deferred = null;
}
promise() {
return this.deferred.promise();
}
}
-> jQuery ์ง์ฐ ๊ฐ์ฒด๋ก ์ํํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. Promise API์ ๋ํด ์ ์์ง ๋ชปํด์ ์ด๋ป๊ฒ ๋ณด์ผ์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ๋ํ ์ด๋ cancel()์ด ํธ์ถ๋๊ณ deferred๊ฐ ํด๊ฒฐ๋์ง ์์ ๊ฒฝ์ฐ deferred๋ฅผ ๊ฑฐ๋ถํ์ง ์์ต๋๋ค. ์๋ง๋ ์ฌ๋๋ค์ ์ด๊ฒ์ด ์ด๋ป๊ฒ ์๋ํด์ผ ํ๋์ง์ ๋ํด ๋ค๋ฅธ ์๊ฒฌ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๊ทธ๋์ ์ฒด์ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
AJAX ์์ฒญ -> ํ์ -> CancellableDeferredInstance -> JQuery ์ง์ฐ -> ๊ตฌ์ฑ ์์
๊ทธ๋ฐ ๋ค์ ์ทจ์ ํ ๋ค์๊ณผ ๊ฐ์ด ๋ณด์ ๋๋ค.
AJAX ์์ฒญ -> ํ์ -> CancellableDeferredInstance /๊ฐ์ฒด ์ฐธ์กฐ๊ฐ ์ด์ null/ JQuery ์ง์ฐ -> ๊ตฌ์ฑ ์์
๋ฐ๋ผ์ AJAX ์์ฒญ์ ๋ ์ด์ ๊ตฌ์ฑ ์์๊ฐ GCd๊ฐ ๋๋ ๊ฒ์ ๋ฐฉ์งํ์ง ์์ต๋๋ค. ์ผ ํ์....]
@benmmurphy ์๋ ํ์ธ์. ์ ๋ JS ๊ฐ๋น์ง ์ปดํ์ผ์ ์ต์ํ์ง ์๊ณ React์์๋ ๋ค๋ฅด๊ฒ ์๋ํ ์ ์์ง๋ง ์ดํด๊ฐ ๋ค๋ฆ ๋๋ค.
makeCancellable
์ฌ์ฉํ๋ฉด React ๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ๋ ๋ ๊ฐ๋น์ง ์์ง์ด ๊ฐ๋ฅํฉ๋๋ค. ์ค๋ช
ํ๊ฒ ์ต๋๋ค.
makeCancellable์ ๊ตฌ์ฑ ์์์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ณด์ ํ๋ ํจ์์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ณด์ ํ๊ฒ ๋๋ ๋ ๋ค๋ฅธ ์ฝ์์ ์์ฑํฉ๋๋ค. makeCancellable ์๋ฃจ์ ์ ๋ถ์ธ ์์ฑ isMounted๋ฅผ ์ฝ์์ผ๋ก ์ฎ๊ธฐ๋ ๊ฒ์ ๋๋ค.
makeCancellable
:
handleError() {
if (this.isMounted()) {
console.log('ERROR')
}
}
makeCancellable
:
promise.then(...).fail((reason) => {
if (reason.isCancelled) return;
console.log('ERROR');
})
makeCancellable
์์ผ๋ฉด ์ฌ์ ํ this
๋ํ ์ฐธ์กฐ๊ฐ ์์ผ๋ฏ๋ก ๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ๋ ๋ ๊ฐ๋น์ง ์์ง๋ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ค๋ฅธ ๊ฒฝ์ฐ์๋ ๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ๋์๋ง์ ์ทจ์ ๊ฐ๋ฅํ ํ๋ผ๋ฏธ์ค์ ์คํจ ํธ๋ค๋ฌ๊ฐ ํธ์ถ๋๋ฏ๋ก ๋ ์ด์ ์ฐธ์กฐ๊ฐ ํ์ํ์ง ์์ต๋๋ค.
@vpontis
๋ฌธ์ ๋ฅผ ์ค๋ช
ํ๋ ๋ช ๊ฐ์ง nodejs ์ฝ๋๊ฐ ์์ต๋๋ค. Foo ๊ตฌ์ฑ ์์๋ ๋น๋๊ธฐ ์ฝ๋ฐฑ resolve
์ด null๋ก ์ค์ ๋ ๊ฒฝ์ฐ์๋ง GC๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ํด๊ฒฐํ๋ ๋ฐ 30์ด๊ฐ ๊ฑธ๋ฆฌ๋ Ajax ์์ฒญ์ ์คํํ๋ฉด ๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๊ตฌ์ฑ ์์๋ 30์ด ๋์ GCd๊ฐ ์๋๋๋ค. ์ด๊ฒ์ isMount()๋ฅผ ๋ ์ด์ ์ฌ์ฉํ์ง ์์์ผ๋ก์จ ํด๊ฒฐํ๋ ค๋ ๋ฌธ์ ์ค ํ๋์
๋๋ค.
npm install promise
npm install weak
node --expose-gc gc.js
first gc Foo {}
after first gc Foo {}
after resolve = null Foo {}
foo gc'd
after second gc {}
https://gist.github.com/benmmurphy/aaf35a44a6e8a1fbae1764ebed9917b6
ํธ์งํ๋ค:
๊ณผ๊ฑฐ ์ด์ผ๊ธฐ๋ฅผ ํด์ ๋ฏธ์ํ์ง๋ง ์ฒ์ ๊ฒ์๋ฌผ์ ์ฝ์์ ๋๋ ๋น์ ์ด ๋งํ๋ ค๋ ์์ ์ ์ดํดํ์ง ๋ชปํ๋๋ฐ ์ง๊ธ์ ์ ๊ฒ ๊ฐ์์. ๋น์ ์ด ๋งํ๋ ค๋ ๊ฒ์ ์ค๋ฅ ์ฝ๋ฐฑ์ด ๊ตฌ์ฑ ์์์ ๋ํ ์ฐธ์กฐ๋ฅผ ํฌํจํ์ง ์๊ธฐ ๋๋ฌธ์(๋๋ ๊ตฌ์ฑ ์์์ ๋ํ ์ฐธ์กฐ๋ฅผ ๋ฐ๋ฅด์ง ์๊ธฐ ๋๋ฌธ์) ๊ตฌ์ฑ ์์๊ฐ ์ฝ์์ ์ํด ์ฐธ์กฐ๋๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ ์ฌ์ค์ ๋๋ค. ๊ธ์, ์ฒซ ๋ฒ์งธ ๋ถ๋ถ์ ์ฌ์ค์ ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ฌํ ์ถ๋ก ์๋ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
1) ์์ ์ ์ค๋ฅ ์ฒ๋ฆฌ๊ธฐ์ ๊ตฌ์ฑ ์์์ ๋ํ ์ฐธ์กฐ๊ฐ ์๋๋ผ๋ then()
์ฝ๋ฐฑ์ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด then
ํธ๋ค์ ์ผ๋ฐ์ ์ผ๋ก this.setState(...)
ํฉ๋๋ค.
2) ์์ ์ ์ค๋ฅ ์ฒ๋ฆฌ๊ธฐ์ ๋๋ถ๋ถ์ ์ค๋ฅ ์ฒ๋ฆฌ๊ธฐ๊ฐ ๊ตฌ์ฑ ์์์ ๋ํ ์ฐธ์กฐ๊ฐ ์๋๋ผ๋. ์๋ฅผ ๋ค์ด ๊ทธ๋ค์ ๋ค์๊ณผ ๊ฐ์ด ํ ๊ฒ์
๋๋ค:
promise.then(...).fail((reason) => {
if (reason.isCancelled) return;
console.log('ERROR');
this.setState({error: true});
})
3) ์ฝ๋๊ฐ then()
์ฝ๋ฐฑ์ ๋ฐ๋ฅด์ง ์๊ณ isCancelled
๋ณ์๋ฅผ ํ์ธํ ํ ํจ์๋ฅผ ์ข
๋ฃํ๋ค๋ ๊ฒ์ ์๊ณ ์์ง๋ง GC๋ ์ด๋ฅผ ์์ง ๋ชปํฉ๋๋ค.
๋ค๋ฅธ ์ฌ๋์ด ๋ด ์์ ๋ ์ด์ ๊ธฐ๋ฐํ ๊ฒ์ ์ฌ์ฉํ๊ธฐ ์ ์ ์ค์ ๋ก GC๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ํ๋๋์ง ํ ์คํธํด์ผ ํฉ๋๋ค. ๋๋ ์์ง ๋ด ๊ฒ์ ํ ์คํธํ์ง ์์์ผ๋ฉฐ ์ด๋ฆฌ์์ ์ค๋ฅ๋ฅผ ๋ฒํ๊ธฐ ๋๋ฌธ์ ์๋ํ์ง ์์ผ๋ฉด ๋๋ผ์ง ์์ ๊ฒ์ ๋๋ค./
์ฝ์ API ์ธก๋ฉด์์ ์ด๊ฒ์ GC ์ธก๋ฉด์์ nodejs์์ ์ ์๊ฒ ํจ๊ณผ์ ์
๋๋ค. ํ์ง๋ง _resolve
, _reject
๋งค๊ฐ๋ณ์๋ฅผ ํด๋ก์ ๊ทผ์ฒ์ ๋์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด๊ฒ์ด JS ์ฌ์์ ๋ฐ๋ผ ์๋ํ๋์ง ๋๋ ์๋ํ๋์ง ํ์คํ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๋
ธ๋๊ฐ ์ผ๋ถ ์ต์ ํ๋ฅผ ์ํํ๊ณ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ตฌํ์ด ๋ณด์ด๋ ๋ชจ๋ ๋ณ์๋ฅผ ์บก์ฒํ๊ฑฐ๋ ํด๋ก์ ์์ ์ฐธ์กฐ๋๋ ๋ณ์๋ง ์บก์ฒํ ์ ์์ต๋๊น? JS๋ฅผ ์ค์ ๋ก ์ดํดํ๋ ์ฌ๋์ด ์ฐจ์๋ฒจ์ ๋ค๊ณ ์ค๋ช
ํ ์ ์์์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. :)
var makeCancelable = (promise) => {
let resolve;
let reject;
const wrappedPromise = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
promise.then((val) => {
if (resolve != null) resolve(val)
});
promise.catch((error) => {
if (reject != null) reject(error)
});
});
return {
promise: wrappedPromise,
cancel() {
resolve = null;
reject = null;
},
};
};
isMounted ํจ์๊ฐ 16.0์์ ์ ๊ฑฐ๋ฉ๋๊น?
@istarkov ์ฝ๋๋ก ์ฝ๊ฐ์ ๊ฐ์ ์ ์ํ ์ ์:
const makeCancelable = (promise) => {
let hasCanceled_ = false
promise.then((val) =>
hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
)
.catch((error) =>
hasCanceled_ ? reject({isCanceled: true}) : reject(error)
)
return {
promise,
cancel() {
hasCanceled_ = true
}
}
}
์๋ก์ด ์ฝ์์ด ๋ถํ์ํ ๋ฟ์ ๋๋ค.
์๋ก์ด ์ฝ์์ด ๋ถํ์ํ ๋ฟ์ ๋๋ค.
@BnayaZil resolve
๋ฐ reject
ํจ์๋ฅผ ํธ์ถํ๊ณ ์์ง๋ง ์ด๋์์ ์๋์ง ๋ช
ํํ์ง ์์ต๋๋ค. Promise.resolve
๋ฐ Promise.reject
๋ฅผ ์๋ฏธํ์ต๋๊น? ์ด ๊ฒฝ์ฐ์๋ ์ฌ์ ํ ์๋ก์ด Promise๋ฅผ ๋ฐํํ ๊ฒ์
๋๋ค.
๋ฉฐ์น ์ ์ fetch() ์์ฒญ์ ์ค๋จํ ์ ์๋ ์ API๊ฐ DOM ์ฌ์์ ์ถ๊ฐ๋์์ต๋๋ค. ์ด API๋ ์์ง ์ด๋ค ๋ธ๋ผ์ฐ์ ์์๋ ๊ตฌํ๋์ง ์์์ง๋ง "abortcontroller-polyfill"์ธ NPM์์ ์ฌ์ฉํ ์ ์๋ ํด๋ฆฌํ์ ๋ง๋ค์์ต๋๋ค. ํด๋ฆฌํ์ ๋ณธ์ง์ ์ผ๋ก @istarkov๊ฐ ๊ฒ์ํ ์ฝ๋์ ๋์ผํ ์์ ์ ์ํ ํ์ง๋ง ๊ตฌํ๋๋ฉด ์ฝ๋ ๋ณ๊ฒฝ ์์ด ์ค์ ๋ธ๋ผ์ฐ์ API๋ก ์ ํํ ์ ์์ต๋๋ค.
์ธ๋ถ ์ ๋ณด:
https://mo.github.io/2017/07/24/abort-fetch-abortcontroller-polyfill.html
React.createClass
๋ ๋ ์ด์ React 16์ ์กด์ฌํ์ง ์๊ณ ์๋ก์ด create-react-class
ํจํค์ง์๋ isMounted
๋ํ ๋ช
ํํ ์ฌ์ฉ ์ค๋จ ๋ฉ์์ง๊ฐ ํฌํจ๋์ด ์์ผ๋ฏ๋ก ์ด๋ฅผ ์ข
๋ฃํ๊ฒ ์ต๋๋ค.
๋๋ @istarkov์ ์๋ฃจ์
์ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋์ผํ๋ค๋ ๊ฒ์ @benmmurphy์ ๋์ isMounted()
๊ฐ ์ฐ๋ ๊ธฐ ์์ง ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์ง ์๊ธฐ ๋๋ฌธ์.
@benmmurphy ์ ์๋ฃจ์ ์ ๋ ๊ฐ๊น์ง๋ง ์๋ชป๋ ๋ณ์๋ฅผ
ํต์ฌ์ ํธ๋ค๋ฌ๋ฅผ ์ญ์ฐธ์กฐํ๋ ํด๋ก์ ๋ฅผ ํตํด ํจ์๋ฅผ ์ ๋ฌํ๋ ๊ฒ์ ๋๋ค.
const makeCancelable = promise => {
let cancel = () => {};
const wrappedPromise = new Promise((resolve, reject) => {
cancel = () => {
resolve = null;
reject = null;
};
promise.then(
val => {
if (resolve) resolve(val);
},
error => {
if (reject) reject(error);
}
);
});
wrappedPromise.cancel = cancel;
return wrappedPromise;
};
์ด ์๋ฃจ์ ์ด ์ด์ ์๋ฃจ์ ์ด ์๋ ๊ฐ๋น์ง ์์ง์ ํ์ฉํ๋ ์ด์ ์ ๋ํ ์ถ๊ฐ ์ค๋ช ์ ์ฌ๊ธฐ ์์ ์ฐพ์ ์
๋๋ ์ด๊ฒ์ npm ํจํค์ง๋ก ์ฐ๋ ๊ธฐํต์ผ๋ก ๋ฐ๊ฟจ์ต๋๋ค . ์ ์ค ์ผ์ด์ค IS ๋ฐ์ํ๊ธฐ ๋๋ฌธ์, ๋๋์ด ๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ์ป์ ๋ ํธ๋์ ์ฝ์๊ณผ์ด๋ฅผ ์ทจ์ํ๋ HOC ์ฑ๋ถ์ผ๋ก, trashable-๋ฐ์ .
ํธ์ง : ๋ด ๋์, ๋ฐฉ๊ธ @hjylewis thrashable ์ ๋ณด์๊ณ ์ฝ์๋ ์ทจ์ํฉ๋๋ค. ์ฌ์ ํ ์๋ ํจํด์ IMO๊ฐ ์ฝ๊ฐ ๊ฐ์ ๋ ๊ฒ์ ๋๋ค.
์ด๋ฌํ ์๋ฃจ์
์ค ์ด๋ ๊ฒ๋ ์ฝ์์ ์ทจ์ํ์ง ์์ผ๋ฉฐ ์์ํ ๋ณด๋ฅ ์ค์ธ ์ฝ์์ ํก์ํ์ฌ ์ฐ์ฅ ์์ด ์ทจ์ํ ์ ์์ต๋๋ค.
function makeCancelable(promise) {
let active = true;
return {
cancel() {active = false},
promise: promise.then(
value => active ? value : new Promise(()=>{}),
reason => active ? reason : new Promise(()=>{})
)
}
}
// used as above:
const {promise, cancel} = makeCancelable(Promise.resolve("Hey!"))
promise.then((v) => console.log(v)) // never logs
cancel()
GC์ ๊ด๋ จํ์ฌ ์์ ํด์ผ ํ ๋ฏธ๋ฌํจ์ด ์์ ์ ์๊ณ ์ปคํผ๊ฐ ์์ง ์์๋์ง ์์์ง๋ง ๊ทธ ํจํด์ ๋ฐํ๋ ์ฝ์์ด ์ค์ ๋ก ์ทจ์๋๊ณ ๋์ถ๋์ง ์๋๋ก ๋ง๋ค ์ ์์ต๋๋ค(๊ณผ๊ฑฐ์ ๊ตฌํํ์ต๋๋ค).
@pygy ๋ต๋ณ ๊ฐ์ฌํฉ๋๋ค!
๋ถํํ๋ ๊ทํ์ ์๋ฃจ์ ์ ์ฌ์ ํ โโ๊ฐ๋น์ง ์ปฌ๋ ์ ์ ํ์ฉํ์ง ์์ต๋๋ค. ๋ณธ์ง์ ์ผ๋ก ์กฐ๊ฑด๋ถ๋ฅผ ์ฌ์ฉํ๋ @istarkov ์ ์๋ฃจ์ ์ ๋ค์ ์์ฑ
์ด ๊ตฌํ์ ํด์งํต์ ๋๊ณ ํ ์คํธ๋ฅผ ์คํํ์ฌ ์ฝ๊ฒ ํ ์คํธํ ์ ์์ต๋๋ค(๊ฐ๋น์ง ์์ง ํ ์คํธ ์คํจ).
๋ํ ๊ตฌํ์์ ์ค๋ฅ๋ฅผ ์ ๋๋ก ์ฒ๋ฆฌํ์ง ๋ชปํฉ๋๋ค.
2018๋ ์ ๋๋ค. ์์์ ์ธ๊ธํ ๊ฒ๋ณด๋ค ๋ ๋์ ์ ๊ทผ ๋ฐฉ์์ด ์์ต๋๊น?
์, ๋ฐ์ ๋ค์ดํฐ๋ธ์ ๋ ๋ฐฐ ํฌ๊ธฐ์ ๋ฌธ์๊ฐ ์์ง๋ง ๋งค์ฐ ์ ๋ฌธ์ ์ธ ์ผ๋ถ ํ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ฝ์ "์ทจ์"์ ๋ํ ์ด๋ฌํ ์ค๋ํซ์ ๊ทธ๋ค์ง ์ข์ IMHO๊ฐ ์๋๋๋ค. ์ทจ์๋ ์ฝ์์ ์๋ ์ฝ์์ด ํด๊ฒฐ๋ ๋๊น์ง ํด๊ฒฐ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ isMounted ํธ๋ฆญ์ ์ฌ์ฉํ ๋๊น์ง ๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.
์ ์ ํ ์ทจ์ ๊ฐ๋ฅํ ํ๋ผ๋ฏธ์ค ๋ํผ๋ ๋ ๋ฒ์งธ ํ๋ผ๋ฏธ์ค์ Promise.race๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์ฆ Promise.race([originalPromise, cancelationPromise])
@benmmurphy ์ ์๋ฃจ์ ์ ๋ ๊ฐ๊น์ง๋ง ์๋ชป๋ ๋ณ์๋ฅผ
๋ด ์๋ฃจ์ ์ด ์๋ํ๋ค๊ณ ์๊ฐํ์ง๋ง ์๋ฐ ์คํฌ๋ฆฝํธ ๋ฐํ์์ด ํ์คํ ์๊ธฐ ์ํด ์ ๊ณตํ๋ ์ฝ์์ ๋ํด ์ถฉ๋ถํ ์์ง ๋ชปํฉ๋๋ค. ํ ์คํธ ํ๋ค์ค์ ๋ ธ๋์์ ์๋ฃจ์ ์ ์คํํ๋ฉด ๊ฐ์ ์ฌ๋ฐ๋ฅด๊ฒ GCํฉ๋๋ค. ๋ด ์๋ฃจ์ ์ ํด๊ฒฐ/๊ฑฐ๋ถ ๊ธฐ๋ฅ์ ๋ ๋์ ๋ฒ์์ ํ ๋นํ ๋ค์ ์ทจ์๊ฐ ํธ์ถ๋ ๋ ์ด๋ฌํ ๊ฐ์ ๋ฌดํจํํ์ต๋๋ค. ๊ทธ๋ฌ๋ ํจ์๋ ํ์ ๋ฒ์์์ ๊ณ์ ์ฌ์ฉํ ์ ์์์ง๋ง ์ฐธ์กฐ๋์ง๋ ์์์ต๋๋ค. ํ๋ ์๋ฐ ์คํฌ๋ฆฝํธ ์์ง์ ์ฐธ์กฐ๋์ง ์๋ ํ ํด๋ก์ ์์ ๋ณ์๋ฅผ ์บก์ฒํ์ง ์๋๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋๋ ์ด๊ฒ์ด ์ฌ๋๋ค์ด ๋ค์๊ณผ ๊ฐ์ ์ผ์ ํ๊ธฐ ๋๋ฌธ์ ์ค์๋ก DOM ๋์๋ฅผ ๋ง๋๋ ํฐ ๋ฌธ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. var element = findDOM(); element.addEventListener('ํด๋ฆญ', function() {}); ๋ฐ ์์๋ ํด๋ก์ ์์ ์ฌ์ฉ๋์ง ์์๋๋ผ๋ ํด๋ก์ ์์ ์ฐธ์กฐ๋ฉ๋๋ค.
@hjylewis @benmmurphy ์ ํธ๋ค๋ฌ๋ฅผ ์ญ์ฐธ์กฐํด์ผ ํฉ๋๊น ?? ํธ๋ค๋ฌ๊ฐ ์คํ๋ ํ์๋ ๊ฐ๋น์ง ์ปฌ๋ ์ ์ด ๋ฐ์ํฉ๋๋ค. ๋ง๋์??
์ฝ์ "์ทจ์"์ ๋ํ ์ด๋ฌํ ์ค๋ํซ์ ๊ทธ๋ค์ง ์ข์ IMHO๊ฐ ์๋๋๋ค. ์ทจ์๋ ์ฝ์์ ์๋ ์ฝ์์ด ํด๊ฒฐ๋ ๋๊น์ง ํด๊ฒฐ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ isMounted ํธ๋ฆญ์ ์ฌ์ฉํ ๋๊น์ง ๋ฉ๋ชจ๋ฆฌ ์ ๋ฆฌ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.
์ ์ ํ ์ทจ์ ๊ฐ๋ฅํ ํ๋ผ๋ฏธ์ค ๋ํผ๋ ๋ ๋ฒ์งธ ํ๋ผ๋ฏธ์ค์ Promise.race๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์ฆ
Promise.race([originalPromise, cancelationPromise])
@hjylewis ์ ๊ด์ฐ์ ์ค์ ๋ก ์๋ํฉ๋๊น? ๋ ธ๋๊ฐ ์ฝํ ์ํ์์ ํ์ธํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ทธ๊ฒ๋ค์ ๋ค์ ๋ณด๋ฉด ๋๋ ๊ทธ๋ค ์ค ์ด๋ ์ชฝ๋ ํน์ดํ ์์ฑ๋ ์ฝ์ ์ฝ๋๊ฐ ์๋๋ผ๋ ๋ฐ ๋์ํฉ๋๋ค. ์ฝ์ ์ฌ์ฉ์๋ก์ ๊ฑฐ๋ถ๋ ์ํ์์ ํด๊ฒฐ๋ '์ทจ์๋' ์ฝ์์ ์์ํ ์ ์์ผ๋ฉฐ ๋ ๋ค ์ด๋ฅผ ์ํํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ตฌ์ฑ ์์์ ๊ฒฝ์ฐ ๊ฑฐ๋ถ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ๋ฌด์ํ๊ธฐ ์ํด ์ถ๊ฐ ์ฝ๋๋ฅผ ์์ฑํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํ๊ธฐ ๋ ์ฌ์ด ์๋ฃจ์ ์ผ ์ ์์ต๋๋ค.
๋๋ ํน์ดํ ๊ฑฐ๋ถ ๊ฐ๋ฅํ ์ฝ์์ด Promise.race([])๋ฅผ ์ฌ์ฉํ์ฌ ์ทจ์ ๊ฐ๋ฅํ ์ฝ์์ ๋ง๋ค ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. Promise๊ฐ ํด๊ฒฐ๋๋ฉด ๋ณด๋ฅ ์ค์ธ ์ฝ๋ฐฑ์ด ์ญ์ ๋์ด ๊ทธ ์์ ์์ ๋ธ๋ผ์ฐ์ ๋คํธ์ํฌ์์ ๊ตฌ์ฑ ์์๋ก์ ์ฐธ์กฐ ์ฒด์ธ์ด ์๊ธฐ ๋๋ฌธ์ ์๋ํฉ๋๋ค. ์๋ํ๋ฉด Race Promise์ ๊ตฌ์ฑ ์์ ์ฌ์ด์ ๋ ์ด์ ์ฐธ์กฐ๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ทจ์ ๊ฐ๋ฅํ ์ฝ์๊ณผ ํจ๊ป Promise.all()
์ฌ์ฉํ๊ณ ๋ธ๋ผ์ฐ์ ์ฝ์์์ ์กํ์ง ์๋ ์ค๋ฅ๋ฅผ ํผํ ์ ์๋์ง ๊ถ๊ธํฉ๋๋ค... ์ฒซ ๋ฒ์งธ ์ทจ์ ์ค๋ฅ๋ง ์ก์ ์ ์๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๊ฒ๋ค์ ์กํ์ง ์์ ์ฑ๋ก ๋จ์ ์์ต๋๋ค.
2018๋ ์ ๋๋ค. ์์์ ์ธ๊ธํ ๊ฒ๋ณด๋ค ๋ ๋์ ์ ๊ทผ ๋ฐฉ์์ด ์์ต๋๊น?
ํ๋ผ๋ฏธ์ค ์คํ์ ์ทจ์ํ๋ ๋ ๋์ ๋ฐฉ๋ฒ, ์ฆ setTimeout, API ํธ์ถ ๋ฑ. 2019๋ ์ ๋๋ค ๐ญ ๐
TC39์์ ์งํ ์ค์ธ Promise ์ทจ์ ์ค๋ ๋๊ฐ ์์ต๋๋ค. (์ ์๊ฐ์๋) ์ฌ๊ธฐ์ ๊ด๋ จ์ด ์์ต๋๋ค(์๋ง๋ .. ํ์คํ์ง ์์).
https://github.com/tc39/proposal-cancellation/issues/24
ํ๋ผ๋ฏธ์ค ์คํ์ ์ทจ์ํ๋ ๋ ๋์ ๋ฐฉ๋ฒ, ์ฆ setTimeout, API ํธ์ถ ๋ฑ. 2019๋ ์ ๋๋ค ๐ญ ๐
์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ ์ฐพ๊ณ ์์ต๋๊น?
const promise = new Promise(r => setTimeout(r, 1000))
.then(() => console.log('resolved'))
.catch(()=> console.log('error'))
.canceled(() => console.log('canceled'));
// Cancel promise
promise.cancel();
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์ด ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ๋ชจ๋ ์ฝ์์ ์ทจ์๋ฅผ ์ถ๊ฐํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํธ์ง: ์ ํ์ฑ/์์ ์ฑ์ ์ํด ์ ๋ฐ์ดํธ๋์์ต๋๋ค.
์ฌ์ฉํ๋ ๋ฐฉ๋ฒ