- id가 'btn'인 button을 클릭하면 서버에 users 리스트를 가져오는 요청을 하고,
- 성공하면 list의 세번째 user의 정보를 다시 요청하여
- 성공하면 user의 profileImage url값을 가져다가 image 태그로 표현하고,
- 이 image를 클릭하면 해당 이미지를 제거.
const script= document.createElement('script')
script.src= 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'
document.body.appendChild(script)
document.body.innerHTML += '<button id="btn">클릭</button>'
document.getElementById('btn').addEventListener('click', function (e) {
$.ajax({
method: 'GET',
url: 'https://api.github.com/users?since=1000',
success: function (data) {
var target = data[2]
$.ajax({
method: 'GET',
url: 'https://api.github.com/user/' + target.id,
success: function (data) {
var _id = 'img' + data.id
document.body.innerHTML += '<img id="' + _id + '" src="' + data.avatar_url + '"/>'
document.getElementById(_id).addEventListener('click', function (e) {
this.remove()
})
},
error: function (err) {
console.error(err)
}
})
},
error: function (err) {
console.error(err)
}
})
})
document.body.innerHTML = '<button id="btn">클릭</button>'
document.getElementById('btn').addEventListener('click', function (e) {
fetch('https://api.github.com/users?since=1000')
.then(function (res) { return res.json() })
.then(function (res) {
var target = res[2]
return fetch('https://api.github.com/user/' + target.id)
})
.then(function (res) { return res.json() })
.then(function (res) {
var _id = 'img' + res.id
document.body.innerHTML += '<img id="' + _id + '" src="' + res.avatar_url + '"/>'
document.getElementById(_id).addEventListener('click', function (e) {
this.remove()
})
})
.catch(function (err) {
console.error(err)
})
})
const script= document.createElement('script')
script.src= 'https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js'
document.body.appendChild(script)
document.body.innerHTML += '<button id="btn">클릭</button>'
document.getElementById('btn').addEventListener('click', function (e) {
axios.get('https://api.github.com/users?since=1000')
.then(function (res) {
var target = res.data[2]
return axios.get('https://api.github.com/user/' + target.id)
})
.then(function (res) {
var _id = 'img' + res.data.id
document.body.innerHTML += '<img id="' + _id + '" src="' + res.data.avatar_url + '"/>'
document.getElementById(_id).addEventListener('click', function (e) {
this.remove()
})
})
.catch(function (err) {
console.error(err)
})
})
- unnsettled (미확정) 상태: pending. thenable하지 않다.
- settled (확정) 상태: resolved. thenable한 상태. (문맥에 따라 다르니 조심할 것)
- fulfilled (성공)
- rejected (실패)
const promiseTest = param => new Promise((resolve, reject) => {
setTimeout(() => {
if (param) {
resolve("해결 완료")
} else {
reject(Error("실패!!"))
}
}, 1000)
})
const testRun = param => promiseTest(param)
.then(text => { console.log(text) })
.catch(error => { console.error(error) })
const a = testRun(true)
const b = testRun(false)
new Promise(function)
.then()
,.catch()
는 언제나 promise를 반환한다.
const executer = (resolve, reject) => { ... }
const prom = new Promise(executer)
const onResolve = res => { ... }
const onReject = err => { ... }
// (1)
prom.then(onResolve, onReject)
// (2)
prom.then(onResolve).catch(onReject)
new Promise((resolve, reject) => { ... })
.then(res => { ... })
.catch(err => { ... })
const simplePromiseBuilder = value => {
return new Promise((resolve, reject) => {
if(value) { resolve(value) }
else { reject(value) }
})
}
simplePromiseBuilder(1)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
simplePromiseBuilder(0)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
const simplePromiseBuilder2 = value => {
return new Promise((resolve, reject) => {
if(value) { resolve(value) }
else { reject(value) }
})
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
}
simplePromiseBuilder2(1)
simplePromiseBuilder2(0)
// 프로미스 실행순서
// resolve 우선 실행시
const prom = new Promise((resolve, reject) => {
resolve()
reject()
console.log('Promise')
})
prom.then(() => {
console.log('then')
})
prom.catch(() => {
console.log('catch')
})
console.log('Hi!')
>> "Promise", "Hi", "then"
>> 전체소스실행하는 과정에서 Promise 인스턴스의 함수도 같이 실행되었다.
-> fullfilled 되면서 then 함수가 queue에 추가됬고
-> 계속 전체소스 실행이 끝나고 나서
-> 다음번 Q에 있는 then 함수가 실행됨
-> reject는 무시되었네?
// reject 우선 실행시
const prom = new Promise((resolve, reject) => {
reject()
resolve()
console.log('Promise')
})
prom.then(() => {
console.log('then')
})
prom.catch(() => {
console.log('catch')
})
console.log('Hi!')
>> "Promise", "Hi", "catch"
>> 전체소스실행하는 과정에서 Promise 인스턴스의 함수도 같이 실행되었다.
-> fullfilled 되면서 then 함수가 queue에 추가됬고
-> 계속 전체소스 실행이 끝나고 나서
-> 다음번 Q에 있는 then 함수가 실행됨
-> resolve는 무시되었네?
위 실행으로 알게된 사실은 다음과 같다.
-
then 이나 catch 구문은 실행큐에 후순위로 등록되고 실행된다.
-
promise 인스턴스에 넘긴 함수 내부에서는 resolve나 reject둘 중에 먼저 호출된 것만 실제로 실행된다.
-
사실 실제로 실행되는게 아니라, 실행은 둘다 되는데, 사실 먼저 둘중 하나를 실행하고 나면 pending의 상태가 fullfilled 로 변하고 현재 Promise의 상태를 끝내라라고 함, pending의 상태가 변하면 다음의 resolve, reject는 의미가 없어짐 그래서
-
결론적으로 사실 실제로 실행되는게 아니라, 실행은 둘다 되는데, pending 상태일 때만 의미가 있기 때문 2번과 같은 결과가 나온다.
Promise.resolve
,Promise.reject
// 뒤를 thenable 하게 만들려고 한 함수
Promise.resolve(42)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
Promise.reject(12)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
- thenable 객체
- thenalbe 은 사실 인터페이스 (duck type )
- then 이라는 method를 가지고 있고, 그 메소드가 resolve 혹은 reject를 실행할 수 있게 되었다면 thenable 하다라고 할 수 있음
- iterator 랑 비슷함
const thenable = {
then (resolve, reject) {
resolve(33)
}
}
const prom1 = Promise.resolve(10)
// Promise.{<resolved>: 10}
const prom = Promise.resolve(thenable)
// 이미 >Promise.{<resolved>: 10} 형태로 then 실행도 안했는데 33을 가지고 있음
// resolve를 시킨다는 건 뭐냐면
// 인자로 thenable 객체가 전달되면, 해당 객체의 then 메소드를 호출해서 resolve 된 결과를 반환
// 인자로 값이 전달되면, 그 값을 resolve 상태로 만듬
prom.then(res => { console.log(res) })
// 그럼 catch 도 되욤? 안됨
const thenable = {
then (resolve, reject) {
resolve(33)
}
}
const prom = Promise.resolve(thenable)
const thenable = {
then (resolve, reject) {
reject(33)
}
}
const prom = Promise.resolve(thenable)
prom.catch(err => { console.log(err) })
-
return 일반값
: promise 객체에 resolved 상태로 반환함. 그 안에 값이 담김Promise(<<resolved>> : 값)
형태로 됨
-
return promise 인스턴스
promise 인스턴스가 리턴된 것
- 프로미스에 인스턴스가 리턴됬으니까 리턴된 애도 프로미스
- 반환된 프로미스 인스턴스도 언젠가 pending에서 resolved 로 바뀔꺼고 다시 then을 태울 수 있음
-
return 을 안하면
return undefined
(원래 JS 동작이 이러함) undefined는 일반값이므로 1) 과 동일한 결과
-
- Promise.resolve(), or Promise.reject() : return 해주지 않는 이상 의미없음
- 그냥 별개의 프로미스 객체가 생성될 뿐, 현재 process 상의 Promise 플로우에 영향을 주지 않음
- 그냥 새로운 promise 일뿐 시퀀스를 따라가지 않음
- 다만 return을 하면 위의 2) 의 new Promise 한것과 동일한 결과
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('첫번째 프라미스')
}, 1000)
}).then(res => {
console.log(res)
return '두번째 프라미스'
}).then(res => {
console.log(res)
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('세번째 프라미스')
}, 1000)
})
}).then(res => {
console.log(res)
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('네번째 프라미스')
}, 1000)
})
}).then(res => {
console.log(res)
}).catch(err => {
console.error(err)
return new Error('이 에러는 then에 잡힙니다.')
}).then(res => {
console.log(res)
// // throw 하면 캐치로 가지만, 프로미스에서는 then 건너뛰고 캐치로 감
throw new Error('이 에러는 catch에 잡힙니다.')
}).then(res => {
console.log('출력 안됨')
}).catch(err => {
console.error(err)
})
- 에러가 나도 여전히 프로미스 객체는 종료되지 않음
- 단지 에러가 났다는 사실을 이해할 수 있음
asyncThing1()
.then(asyncThing2)
.then(asyncThing3)
.catch(asyncRecovery1)
.then(asyncThing4, asyncRecovery2)
.catch(err => { console.log("Don't worry about it") })
.then(() => { console.log("All done!") })
- iterable의 모든 요소가 fulfilled되는 경우: 전체 결과값들을 배열 형태로 then에 전달.
- iterable의 요소 중 일부가 rejected되는 경우: 가장 먼저 rejected 되는 요소 '하나'의 결과를 catch에 전달.
const arr = [
1,
new Promise((resolve, reject) => {
setTimeout(()=> {
resolve('resolved after 1000ms')
}, 1000)
}),
'abc',
() => 'not called function',
(() => 'IIFE')()
]
Promise.all(arr)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
const arr = [
1,
new Promise((resolve, reject) => {
setTimeout(()=> {
reject('rejected after 1000ms')
}, 1000)
}),
'abc',
()=> 'not called function',
(()=> 'IIFE')()
]
Promise.all(arr)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
- iterable의 요소 중 가장 먼저 fulfilled / rejected되는 요소의 결과를 then / catch에 전달.
const arr = [
new Promise(resolve => {
setTimeout(()=> { resolve('1번요소, 1000ms') }, 1000)
}),
new Promise(resolve => {
setTimeout(()=> { resolve('2번요소, 500ms') }, 500)
}),
new Promise(resolve => {
setTimeout(()=> { resolve('3번요소, 750ms') }, 750)
})
]
Promise.race(arr)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })
const arr = [
new Promise(resolve => {
setTimeout(()=> { resolve('1번요소, 0ms') }, 0)
}),
'no queue'
]
Promise.race(arr)
.then(res => { console.log(res) })
.catch(err => { console.error(err) })