๋๊ธฐํ
์ฝ๋์ ์ง์ฌ์ง ์์๋๋ก ๊ฒฐ๊ณผ๊ฐ์ด ๋์ถ๋๋ค.
function waitSyns(ms) {
var start = Date.now();
var now = start;
while(now - start < ms ) {
now = Date.now();
}
} // ํ์ฌ ์๊ฐ๊ณผ ์์ ์๊ฐ์ ๋น๊ตํ๋ฉฐ ms ๋ฒ์ ๋ด์์ ๋ฌดํ ๋ฃจํ๋ฅผ ๋๋ blocking ํจ์์
๋๋ค.
function drink(person, coffee) {
console.log(person + '๋ ' + coffee + '๋ฅผ ๋ง์ญ๋๋ค');
}
function orderCoffeeSync(coffee) {
console.log(coffee + '๊ฐ ์ ์๋์์ต๋๋ค');
waitSyns(4000);
return coffee;
}
let customers = [{
name: 'Steve',
request: '์นดํ๋ผ๋ผ'
}, {
name: 'John',
request: '์๋ฉ๋ฆฌ์นด๋
ธ'
}];
// call synchronously
customers.forEach(function(customer) {
let coffee = orderCoffeeSync(customer.request);
drink(customer.name, coffee);
});
// ์ถ๋ ฅ๊ฐ:
์นดํ๋ผ๋ผ๊ฐ ์ ์๋์์ต๋๋ค
Steve๋ ์นดํ๋ผ๋ผ๋ฅผ ๋ง์ญ๋๋ค
์๋ฉ๋ฆฌ์นด๋
ธ๊ฐ ์ ์๋์์ต๋๋ค
John๋ ์๋ฉ๋ฆฌ์นด๋
ธ๋ฅผ ๋ง์ญ๋๋ค
๋น๋๊ธฐ – ๋์์ ์ฌ๋ฌ ์์ ์ ํด๋ณผ ์ ์๋ค!
๋น๋๊ธฐ ์ฒ๋ฆฌ๋, ํน์ ๋ก์ง์ ์คํ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ฃผ์ง ์๊ณ ๋๋จธ์ง ์ฝ๋๋ฅผ ๋จผ์ ์คํํ๋ ๊ฒ
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ์ด์ ๋, ํ๋ฉด์์ ์๋ฒ๋ก ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ์ ๋ ์๋ฒ๊ฐ ์ธ์ ๊ทธ ์์ฒญ์ ๋ํ ์๋ต์ ์ค์ง๋ ๋ชจ๋ฅด๋๋ฐ ๋ง๋ฅ ๋ค๋ฅธ ์ฝ๋๋ฅผ ์คํ ์ ํ๊ณ ๊ธฐ๋ค๋ฆด ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ์๋๊ณ ๋๊ธฐ ์ฒ๋ฆฌ๋ผ๋ฉด ์ฝ๋ ์คํํ๊ณ ๊ธฐ๋ค๋ฆฌ๊ณ , ์คํํ๊ณ ๊ธฐ๋ค๋ฆฌ๊ณ .. ์๋ง ์น์ ์คํํ๋๋ฐ ์์ญ ๋ถ์ ๊ฑธ๋ฆด ๊ฒ์ด๋ค.
๋น๋๊ธฐ์ ์ฃผ์ ์ฌ๋ก
- DOM Element์ ์ด๋ฒคํธ ํธ๋ค๋ฌ
- ๋ง์ฐ์ค, ํค๋ณด๋ ์ ๋ ฅ (click, keydown ๋ฑ)
- ํ์ด์ง ๋ก๋ฉ (DOMContentLoaded ๋ฑ)
- ํ์ด๋จธ
- ํ์ด๋จธ API (setTimeout ๋ฑ)*
- ์ ๋๋ฉ์ด์ API (requestAnimationFrame)*
- ์๋ฒ์ ์์ ์์ฒญ ๋ฐ ์๋ต
- fetch API*
- AJAX (XHR)*
*๋ ๊ณต๋ถํ๊ธฐ
https://developer.mozilla.org/ko/docs/Web/JavaScript/EventLoop
function waitAsync(callback, ms) {
setTimeout(callback, ms);
}
function drink(person, coffee) {
console.log(person + '๋ ' + coffee + '๋ฅผ ๋ง์ญ๋๋ค');
}
let customers = [{
name: 'Steve',
request: '์นดํ๋ผ๋ผ'
}, {
name: 'John',
request: '์๋ฉ๋ฆฌ์นด๋
ธ'
}];
function orderCoffeeAsync(menu, callback) {
console.log(menu + '๊ฐ ์ ์๋์์ต๋๋ค');
waitAsync(function() {
callback(menu);
}, 4000);
}
// call asynchronously
customers.forEach(function(customer) {
orderCoffeeAsync(customer.request, function(coffee) {
drink(customer.name, coffee);
});
});
//์ถ๋ ฅ๊ฐ
์นดํ๋ผ๋ผ๊ฐ ์ ์๋์์ต๋๋ค
์๋ฉ๋ฆฌ์นด๋
ธ๊ฐ ์ ์๋์์ต๋๋ค
Steve๋ ์นดํ๋ผ๋ผ๋ฅผ ๋ง์ญ๋๋ค
John๋ ์๋ฉ๋ฆฌ์นด๋
ธ๋ฅผ ๋ง์ญ๋๋ค
setTimeout
setTimeout ํจ์์ ์ฒซ๋ฒ์งธ ์ธ์๋ ๊ธฐ๋ค๋ฆฐ ํ์ ์คํ์ํฌ ํจ์, ๊ทธ ๋ค์์ ๊ธฐ๋ค๋ฆด ๋ฐ๋ฆฌ์ด(delay) ์ด๋ค.
ํ์ง๋ง setTimeout์ delay์ธ์๊ฐ delay ms ํ์ ์คํ ๋๋ ๊ฒ์ ๋ณด์ฅํ์ง ์๋๋ค. ์ ํํ๋ delay ms ํ์ Callback Queue์ ๋ค์ด๊ฐ๋ ๊ฒ์ ๋ณด์ฅํ๋ค.
๋น๋๊ธฐ ํจ์ ์ ๋ฌ ํจํด
๋น๋๊ธฐ ํจ์ ์ ๋ฌ ํจํด 1 : callback ํจํด
let request = 'caffelatte';
orderCoffeeAsync(request, function(response) {
// response -> ์ฃผ๋ฌธํ ์ปคํผ ๊ฒฐ๊ณผ
drink(response);
});
๋น๋๊ธฐ ํจ์ ์ ๋ฌ ํจํด 2 : ์ด๋ฒคํธ ๋ฑ๋ก ํจํด // ์ด๋ฒคํธ ๋ฆฌ์คํธ๋ฅผ ๊ฐ์ง๊ณ ์๋ ํจํด์ด๋ผ๋ฉด!
let request = 'caffelatte';
orderCoffeeAsync(request).onready = function(response) {
// response -> ์ฃผ๋ฌธํ ์ปคํผ ๊ฒฐ๊ณผ
drink(response);
};
Callback = ๋น๋๊ธฐ ํจ์์ ์์๋ฅผ ์ ์ดํ๊ณ ์ถ์๋
const printString = (string) => {
setTimeout(
() => {
console.log(string)
},
Math.floor(Math.random() * 100) + 1
)
}
const printAll = () => {
printString("a")
printString("b")
printString("c")
}
printAll()
// ์ถ๋ ฅ๊ฐ
a
c
b
๋๋ค์ผ๋ก ๋์จ๋ค.
const printString = (string, callback) => {
setTimeout(
() => {
console.log(string)
callback()
},
Math.floor(Math.random() * 100) + 1
)
}
const printAll = () => {
printString("a", () => {
printString("b", () => {
printString("c", () => {}) // ์ฝ๋ฐฑํฌ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
})
})
}
printAll()
// ์ถ๋ ฅ๊ฐ
a
b
c
์ธ์ ๋ a ,b, c ์์๋๋ก ๋์จ๋ค.
๊ทธ ์ด์ ๋ printString ๋ช
์ ํจ์์์ callback์ด setTimeout ํจ์๊ฐ ๋๋๋ setTimeout์ ์ฝ๋ฐฑ์ ์ด callback์ ์คํํด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
callback error handling design & usage
const somethingGonnaHappen = callback => {
waitingUnitlSomethingHappens()
if(isSomethingGood) {
callback(null, something)
}
if(isSomethingBad) {
callback(something, null)
}
}
somethingGonnaHappen((err, data) => {
if(err) {
console.log('ERR!!');
return;
}
return data;
})
Promise = ์๋ฐ์คํฌ๋ฆฝํธ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ์ฌ์ฉ๋๋ ๊ฐ์ฒด
callback์ ์ธ์๋ก ๋ฐ์ง ์๊ณ , ์๋ก์ด Promise๋ฅผ ๋ฆฌํดํ๋ค.
์ด Promise๋ resolve์ reject๋ฅผ ์ธ์๋ก ๋ฐ๋ callback์ ์คํํ๊ฒ ๋๋ค.
ES6/ES2015 ์์ ์๊ฐ๋ Job Queue๋ Callback Queue์ ๋ค๋ฅธ Queue์ด๋ฉฐ Promise๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ Job Queue๋ฅผ ์ฌ์ฉํ๋ค. promise๋ฅผ ์ฌ์ฉํ ๋ callback ํจ์ ์ญํ ์ ํ๋ .then ์ ์ฌ์ฉํ๊ฒ ๋๋ฉฐ, ์ด๋ฐ thenableํ ํจ์๋ค์ Job Queue์ ์ถ๊ฐ๋๋ค.
Job Queue์ ์ฐ์ ์์๊ฐ Callback Queue๋ณด๋ค ๋์์, Event Loop๋ Call Stack์ด ๋น์ด์์ ๊ฒฝ์ฐ, Job Queue์์ ๊ธฐ๋ค๋ฆฌ๋ ๋ชจ๋ ์์ ์ ์ฒ๋ฆฌํ๊ณ Callback Queue๋ก ์ด๋ํ๊ฒ ๋๋ค.
const printString = (string) => {
return new Promise((resolve, reject) => {
setTimeout(
() => {
console.log(string)
resolve()
},
Math.floor(Math.random() * 100) + 1
)
})
}
const printAll = () => {
printString('A')
.then(() => {
return printString("B")
})
.then(() => {
return printString("C")
})
}
printAll()
// ์ถ๋ ฅ๊ฐ
A
B
C
Promise ๋ ์ฒซ ์๋ฌด๊ฐ ๋๋๊ณ .then์ผ๋ก ๋ค์ ์๋ฌด๋ฅผ ์งํํ ์ ์๋ค.
reject๋ก ์๋ฌ์ฒ๋ฆฌ๊ฐ ๋๋ ๊ฒฝ์ฐ์๋ .catch๋ฅผ ์ด์ฉํด์ ์๋ฌ ํธ๋ค๋ง์ ๋ง์ง๋ง ์ฒด์ธ์์ ํ ์ ์๋ค.
๋ง์ฝ callback์์ ์๋ฌ๋ฅผ ๋๊ฒจ์ฃผ๋ ํจ์๊ฐ ์์๋ค๋ฉด ์ฝ๋ฐฑ์ ์ฒ๋ฆฌํ ๋๋ง๋ค ์๋ฌ์ฒ๋ฆฌ๋ฅผ ํด์ผํ๋ค.
Promise Hell
function gotoCodestates() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`1. go to codestates`)}, 100)
})
}
function sitAndCode() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`2. sit and code`)}, 100)
})
}
function eatLunch() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`3. eat lunch`)}, 100)
})
}
function gotoBed() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`4. gotoBed`)}, 100)
})
}
gotoCodestates()
.then(data => {
console.log(data)
sitAndCode()
.then(data => {
console.log(data)
eatLunch()
.then(data => {
console.log(data)
gotoBed()
.then(data => {
console.log(data)
})
})
})
})
// ์ถ๋ ฅ๊ฐ
1. go to codestates
2. sit and code
3. eat lunch
4. gotoBed
Promise Chaining
return์ ํตํด์ ํด๋น ๋น๋๊ธฐ๋ฅผ ๋ค์ ๋ค์์ผ๋ก ๋๊ธด๋ค.
promise์ ๊น๋ํจ์ ์ ์งํ ์ ์๊ณ , ์ฝ๋ฐฑ์ ํผํ ์ ์๋ค.
function gotoCodestates() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`1. go to codestates`)}, 100)
})
}
function sitAndCode() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`2. sit and code`)}, 100)
})
}
function eatLunch() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`3. eat lunch`)}, 100)
})
}
function gotoBed() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`4. gotoBed`)}, 100)
})
}
gotoCodestates()
.then(data => {
console.log(data)
return sitAndCode()
})
.then(data => {
console.log(data)
return eatLunch()
})
.then(data => {
console.log(data)
return gotoBed()
})
.then(data => {
console.log(data)
})
// ์ถ๋ ฅ๊ฐ
1. go to codestates
2. sit and code
3. eat lunch
4. gotoBed
async await
await๋ผ๋ ๊ฒ์ผ๋ก ๋น๋๊ธฐ ํจ์๋ค์ ๋ง์น ๋๊ธฐ์ ์ธ ํ๋ก๊ทธ๋๋ฐ์ธ ๊ฒ์ฒ๋ผ ์ธ ์ ์๋ค.
์ค์ ๋ก ๋์๊ฐ๋ ๊ฒ์ promise์ ๋์ผํ๊ฒ ๋์๊ฐ๋๋ฐ ํํ์์ฒด๋ฅผ ๋๊ธฐ์ ์ ์ธ ์ ์๋ค. ํํ ๊ฐ๋ ์ฑ์ด ์ข๋ค.
์์ฐจ์ ์ผ๋ก ๋์๊ฐ๋ค. ๊ธฐ๋ค๋ฆฐ๋ค๋ ๊ฒ์ด๋ค.
function gotoCodestates() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`1. go to codestates`)}, 100)
})
}
function sitAndCode() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`2. sit and code`)}, 100)
})
}
function eatLunch() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`3. eat lunch`)}, 100)
})
}
function gotoBed() {
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(`4. gotoBed`)}, 100)
})
}
const result = async () => {
const one = await gotoCodestates();
console.log(one);
const two = await sitAndCode();
console.log(two);
const three = await eatLunch();
console.log(three);
const four = await gotoBed();
console.log(four);
};
result();
// ์ถ๋ ฅ๊ฐ
1. go to codestates
2. sit and code
3. eat lunch
4. gotoBed
์ ๋ฆฌ
1. ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์ ๋น๋๊ธฐ๋ก ๋์๊ฐ์ผํ ๊น?
๋น๋๊ธฐ ์ฒ๋ฆฌ๋, ํน์ ๋ก์ง์ ์คํ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ฃผ์ง ์๊ณ ๋๋จธ์ง ์ฝ๋๋ฅผ ๋จผ์ ์คํํ๋ ๊ฒ
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ์ด์ ๋, ํ๋ฉด์์ ์๋ฒ๋ก ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ์ ๋ ์๋ฒ๊ฐ ์ธ์ ๊ทธ ์์ฒญ์ ๋ํ ์๋ต์ ์ค์ง๋ ๋ชจ๋ฅด๋๋ฐ ๋ง๋ฅ ๋ค๋ฅธ ์ฝ๋๋ฅผ ์คํ ์ ํ๊ณ ๊ธฐ๋ค๋ฆด ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋น๋๊ธฐ ์ฒ๋ฆฌ๊ฐ ์๋๊ณ ๋๊ธฐ ์ฒ๋ฆฌ๋ผ๋ฉด ์ฝ๋ ์คํํ๊ณ ๊ธฐ๋ค๋ฆฌ๊ณ , ์คํํ๊ณ ๊ธฐ๋ค๋ฆฌ๊ณ .. ์๋ง ์น์ ์คํํ๋๋ฐ ์์ญ ๋ถ์ ๊ฑธ๋ฆด ๊ฒ์ด๋ค.
2. callback = ๋น๋๊ธฐ๋ก ๋์๊ฐ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ ์ดํ๋ ๋ฐฉ๋ฒ
3. promise = ์ฌ์ฉํ๊ธฐ ์ด๋ ค์ด callback์ ๋์ ํ์ฌ ์ฝ๊ณ ํธํ๊ฒ ๋น๋๊ธฐ ํจ์๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
4. promise๋ promise hell์ ๋น ์ง ์ ์๊ธฐ์ promise chaining์ ์ ์ ํ ์ฌ์ฉํด์ผํ๋ค.
5. async await๋ฅผ ์จ์ promise๋ฅผ ์ผ๋ฐํจ์์ฒ๋ผ ์ธ ์ ์๊ฒ ๋๋ค.
๊ฐ๋จํ ์ด๋ฒคํธ ๋ฃจํ์ ์๋ ์๋ฆฌ
์ด๊ฒ์ ์คํ์ด ๋น์ด์์๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ฒ ํ๊ธฐ ์ํด์์ด๋ค.
setTimeout 0์ด ์คํ๋๋ฉด Web API๋ ๋ฐ๋ก ์ข ๋ฃํ๊ณ ํ์ ์ฝ๋ฐฑ์ ์ง์ด๋ฃ๋๋ค. ์ด๋ฒคํธ ๋ฃจํ๋ ์คํ์ด ๋น์์ง๋๊น์ง ๊ธฐ๋ค๋ฆฐ ํ์ ํ์ ์๋ ์ฝ๋ฐฑ์ ์คํ์ ์์ ์ ์๋ค. ์คํ์ ๊ณ์ํด์ ์คํ์ ํ๋ค. console.log('hailie')๋ฅผ ์คํํ๊ณ ์คํ์ด ์ ๋ฆฌ๊ฐ ๋๋ค. ์ด์ ์ด๋ฒคํธ ๋ฃจํ๊ฐ ๊ฐ์ ํด์ ์ฝ๋ฐฑ์ ํธ์ถํ๋ค. ์ด๊ฒ์ด setTimeout 0์ด ์ด ์ฝ๋ ์คํ์ ์ด๋ค ์ด์ ์์ ๊ฐ ์คํ์ ๋ง์ง๋ง๊น์ง ์ง์ฐ์ํค๋ ์ด์ ์ด๋ค. ์ ํํ๋ ์คํ์ด ๋น์์ง๋๊น์ง๊ฒ ์ง.
์ฝ๋ฐฑ์ ๋ค๋ฅธ ํจ์๊ฐ ๋ถ๋ฅด๋ ํจ์์ด๋ค. ํน์ ์์ผ๋ก ํ์ ์์ผ ๋น๋๊ธฐ์ ์ฝ๋ฐฑ์ด๋ผ๊ณ ๋ฌ์ฌํ ์ ์๋ค.
์ฐธ์กฐ "event loop"
https://www.youtube.com/watch?v=8aGhZQkoFbQ
์ฐธ์กฐ *call stack*
์ฐธ์กฐ"js๋น๋๊ธฐ"
https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/