산채 하나의 Promise
Promise 는 이 보 를 작성 하 는 또 다른 방식 입 니 다. 저 는 어 리 석 습 니 다. 바로 Callback 의 패키지 입 니 다.
Callback 에 비해 다음 과 같은 특징 이 있 습 니 다.
let p1 = new Promise((resolve) => {
fs.readFile('./test.js', 'utf8', (err, data) => {
resolve(data)
})
})
p1.then(data => console.log(data))
p1.then(data => console.log(data.toUpperCase()))
Callback 으로 똑 같은 효 과 를 낼 수 있 습 니 다.
이렇게
let callbacks = []
function resolve(data){
callbacks.forEach(cb => cb(data))
}
fs.readFile('./test.js', 'utf8', (err, data) => {
resolve(data)
})
callbacks.push(data => console.log(data))
callbacks.push(data => console.log(data.toUpperCase()))
상기 코드 를 밀봉 하 다.
const fs = require('fs')
class FakePromise {
constructor(fn){
this.callbacks = []
resolve = resolve.bind(this)
function resolve(data){
this.callbacks.forEach(cb => cb(data))
}
fn(resolve)
}
then(onFulfilled){
this.callbacks.push(onFulfilled)
}
}
let p1 = new FakePromise(resolve => {
fs.readFile('./test.js', 'utf8', (err, data) => {
resolve(data)
})
})
p1.then(data => console.log(data))
p1.then(data => console.log(data.toUpperCase()))
하?진짜 Promise 랑 비슷 하지 않 아 요?
게시 - 구독 모드 의 측면 에서 볼 때:
.then(onFulfilled)
메 시 지 를 구독 하고 비동기 결 과 를 등록 처리 하 는 함수 resolve(data)
을 통 해 메 시 지 를 발표 하고 비동기 결 과 를 처리 하 는 함 수 를 실행 합 니 다. 발표 시 기 는 비동기 사건 이 완 료 될 때 지연 해결
이전 코드 에 문제 가 있 습 니 다. 실행
p1.then(data => console.log(data))
하기 전에 resolve(data)
이미 실행 되 었 다 면 .then(onFulfilled)
등 록 된 비동기 결 과 를 처리 하 는 함 수 는 영원히 실행 되 지 않 을 것 입 니 다.이러한 상황 을 피하 기 위해 resolve 함 수 를 개조 하고 내부 에 setTimeout 을 추가 하여 등 록 된 처리 함수 가 다음 이벤트 대기 열 에서 실 행 될 수 있 도록 합 니 다. 이렇게
function resolve(value) {
setTimeout(() => {
this.callbacks.forEach(cb => cb(value))
}, 0)
}
resolve 내부 함수 지연 을 통 해 먼저 구독 메 시 지 를 확보 하고 메 시 지 를 발표 합 니 다.
그러나 Promise 는 메 시 지 를 발표 한 후에 도 메 시 지 를 구독 하고 즉시 실행 할 수 있 는 추가 기능 도 있다.
const fs = require('fs')
let p1 = new Promise(resolve => {
fs.readFile('./test.js', 'utf8', (err, data) => resolve(data))
})
p1.then(data => console.log(data))
setTimeout(function(){
p1.then(data => console.log(data.toUpperCase()))
}, 5000)
5s 내 에 파일 을 읽 는 데 성 공 했 지만 5s 이후 에 도
.then
등록 을 통 해 사건 을 처리 할 수 있 고 이 사건 은 즉시 실 행 될 것 입 니 다.먼저 발표 하고 구독 하 다
먼저 발표 하고 구독 하 는 기 초 는 메 시 지 를 저장 하 는 것 이다.그 다음 에 상 태 를 기록 하고 메시지 가 발표 되 었 는 지 판단 해 야 합 니 다. 만약 에 메 시 지 를 발표 하지 않 으 면
.then
을 통 해 리 셋 을 등록 할 때 리 셋 함 수 를 내부 리 셋 대기 열 에 추가 합 니 다.메시지 가 발표 되면 .then
를 통 해 리 셋 을 등록 할 때 리 셋 함수 에 메 시 지 를 직접 전달 하고 실행 합 니 다.Promise 규범 에서 사용 하 는 상태 체 제 는
pending
, fulfilled
, rejected
이다.pending
는 fulfilled
또는 rejected
로 전환 할 수 있 고 한 번 만 전환 할 수 있다.fulfilled
와 rejected
로 전환 하면 상 태 는 더 이상 변 할 수 없다.수정 코드 는 다음 과 같 습 니 다.
class FakePromise {
constructor(fn) {
this.value = null
this.state = 'pending'
this.callbacks = []
resolve = resolve.bind(this)
function resolve(value) {
setTimeout(() => {
this.value = value
this.state = 'fulfilled'
this.callbacks.forEach(cb => cb(value))
}, 0)
}
fn(resolve)
}
then(onFulfilled) {
if (this.state === 'pending') {
this.callbacks.push(onFulfilled)
} else {
onFulfilled(this.value)
}
}
}
먼저 발표 하고 구독 하 는 것 이 이 루어 졌 으 니 resolve 의 setTimeout 은 지 울 수 있 지 않 습 니까?
안 돼 요. 진지 한 Promise 가 그 렇 기 때 문 이에 요.
let p1 = new Promise(resolve => {
resolve('haha')
})
p1.then(data => console.log(data))
p1.then(data => console.log(data.toUpperCase()))
console.log('xixi')
// xixi
// haha
// HAHA
Resolve 에서 setTimeout 을 유지 해야만 Fake Promise 가 같은 효 과 를 낼 수 있 습 니 다.
let p1 = new FakePromise(resolve => {
resolve('haha')
})
p1.then(data => console.log(data))
p1.then(data => console.log(data.toUpperCase()))
console.log('xixi')
// xixi
// haha
// HAHA
setTimeout 의 출력 결과 가 없습니다.
// haha
// HAHA
// xixi
체인 프로 미스
진지 한 Promise 는 연쇄 적 으로 호출 되 어 지옥 으로 돌아 가 는 것 을 피 할 수 있다.
let p1 = new Promise(resolve => {
fs.readFile('./test.js', 'utf8', (err, data) => {
resolve(data)
})
}).then(res => {
return new Promise(resolve => {
fs.readFile('./main.js', 'utf8', (err, data) => {
resolve(data)
})
})
}).then(res => {
console.log(res)
})
진지 한 Promise 호출 then 방법 은 새로운 Promise 대상 을 되 돌려 줍 니 다.
우리 가 위조 한 Fake Promise 는 이 기능 을 실현 하지 못 했 습 니 다. 원래 의 then 방법 입 니 다.
...
then(onFulfilled){
if (this.state === 'pending') {
this.callbacks.push(onFulfilled)
} else {
onFulfilled(this.value)
}
}
...
원래 의 then 방법 은 state 에 따라 onFulfilled 함 수 를 등록 하 는 지, 아니면 onFulfilled 함 수 를 실행 하 는 지 판단 하 는 것 입 니 다.
Fake Promise 의 높 은 모방 을 실현 하기 위해 서 는 then 방법 을 개조 하여 새로운 Fake Promise 로 되 돌려 야 합 니 다. 쉽게 구분 하기 위해 돌아 오 는 Fake Promise 를 SonFake Promise 라 고 지 었 고, 이전에 then 대상 을 Father Fake Promise 로 호출 했 습 니 다.
그러면 문제 가 왔 습 니 다.
우선, 새로운 SonFake Promise 를 만 들 때 들 어 오 는 함수 인자 fn 을 한 번 실행 하고 이 함수 에는 resolve 인자 가 있 습 니 다.
...
then(onFulfilled){
if(this.state === 'pending'){
this.callbacks.push(onFulfilled)
let SonFakePromise = new FakePromise(function fn(resolve){
})
return SonFakePromise
}else{
onFulfilled(this.value)
let SonFakePromise = new FakePromise(function fn(resolve){
})
return SonFakePromise
}
}
...
지금 문 제 는 이 SonFake Promise 가 언제 해 결 됩 니까?즉, 구조 함수 중의 함수 매개 변수 fn 은 어떻게 정의 합 니까?
진지 한 Promise 의 예 를 결합 해 보면
let faherPromise = new Promise(resolve => {
fs.readFile('./test.js', 'utf8', (err, data) => {
resolve(data)
})
}).then(res => {
return new Promise(resolve => {
fs.readFile('./main.js', 'utf8', (err, data) => {
resolve(data)
})
})
}).then(res => {
console.log(res)
})
//
let faherPromise = new Promise(resolve => {
fs.readFile('./test.js', 'utf8', (err, data) => {
resolve(data)
})
})
let sonPromise = faherPromise.then(function onFulfilled(res){
return new Promise(function fn(resolve){
fs.readFile('./main.js', 'utf8', (err, data) => {
resolve(data)
})
})
}).then(res => {
console.log(res)
})
예 에서 onFulfilled 함 수 는 다음 과 같 으 며, 실행 후 새로운 Promise 로 되 돌아 가 fulPromise 라 고 잠시 이름 을 지 었 습 니 다.
function onFulfilled(res) {
return new Promise(function fn(resolve){
fs.readFile('./main.js', 'utf8', (err, data) => {
resolve(data)
})
})
}
이제 father Promise, son Promise 와 fulPromise 의 관 계 를 분석 해 보 겠 습 니 다.
let fatherPromise = new Promise(function fatherFn(fatherResolve){
fs.readFile('./test.js', 'utf8', (err, data) => {
fatherResolve(data)
})
})
let sonPromise = fatherPromise.then(retFulPromise)
function retFulPromise(res) {
let fulPromise = new Promise(function fulFn(fulResolve){
fs.readFile('./main.js', 'utf8', (err, data) => {
fulResolve(data)
})
})
return fulPromise
}
father Promise 의 상태 가 fulfilled 일 때 retFulPromise 를 실행 하고 fulPromise 로 돌아 갑 니 다. 이 fulPromise 가 fulResolve 를 실행 할 때 main. js 읽 기 가 완료 되면 sonPromise 도 내부 resolve 를 실행 합 니 다.
그래서 sonPromise 의 sonResolve 함수 도 fulPromise 에 등록 되 었 다 고 볼 수 있 습 니 다.
So, 전체 절 차 를 알 게 되 었 습 니 다. 자신의 Fake Promise 를 어떻게 수정 해 야 합 니까?
쇼 조작, 기 교 를 시험 할 때 가 되 었 습 니 다. sonResolve 의 인용 을 저장 하고 fulFake Promise 에 등록 합 니 다.
const fs = require('fs')
class FakePromise {
constructor(fn) {
this.value = null
this.state = 'pending'
this.callbacks = []
resolve = resolve.bind(this)
function resolve(value) {
setTimeout(() => {
this.value = value
this.state = 'fulfilled'
this.callbacks.forEach(cb => {
let returnValue = cb.onFulfilled(value)
if (returnValue instanceof FakePromise) {
returnValue.then(cb.sonResolveRes)
}
})
})
}
fn(resolve)
}
then(onFulfilled) {
if (this.state === 'pending') {
let sonResolveRes = null
let sonFakePromise = new FakePromise(function sonFn(sonResolve) {
sonResolveRes = sonResolve
})
this.callbacks.push({
sonFakePromise,
sonResolveRes,
onFulfilled
})
return sonFakePromise
} else {
let value = onFulfilled(this.value)
let sonResolveRes = null
let sonFakePromise = new FakePromise(function sonFn(sonResolve) {
sonResolveRes = sonResolve
})
if (value instanceof FakePromise) {
value.then(sonResolveRes)
}
return sonFakePromise
}
}
}
다각도 테스트
let fatherFakePromise = new FakePromise(resolve => {
fs.readFile('./test.js', 'utf8', (err, data) => {
resolve(data)
})
})
let sonFakePromise = fatherFakePromise.then(function onFulfilled(res) {
return new FakePromise(function fn(resolve) {
fs.readFile('./main.js', 'utf8', (err, data) => {
resolve(data)
})
})
}).then(res => {
console.log(res)
})
let fatherFakePromise = new FakePromise(resolve => {
fs.readFile('./test.js', 'utf8', (err, data) => {
resolve(data)
})
})
setTimeout(function () {
let sonFakePromise = fatherFakePromise.then(function onFulfilled(res) {
return new FakePromise(function fn(resolve) {
fs.readFile('./main.js', 'utf8', (err, data) => {
resolve(data)
})
})
}).then(res => {
console.log(res)
})
}, 1000)
let fatherFakePromise = new FakePromise(resolve => {
resolve('haha')
})
let sonFakePromise = fatherFakePromise.then(function onFulfilled(res) {
return new FakePromise(function fn(resolve) {
fs.readFile('./main.js', 'utf8', (err, data) => {
resolve(data)
})
})
}).then(res => {
console.log(res)
})
let fatherFakePromise = new FakePromise(resolve => {
resolve('haha')
})
setTimeout(function () {
let sonFakePromise = fatherFakePromise.then(function onFulfilled(res) {
return new FakePromise(function fn(resolve) {
fs.readFile('./main.js', 'utf8', (err, data) => {
resolve(data)
})
})
}).then(res => {
console.log(res)
})
}, 1000)
참고 자료
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
SPA 비동기 데이터 흐름결국, 프론트엔드는 백엔드의 데이터를 받은 후, 이를 가공하여 사용자에게 어떠한 방식으로 전달하느냐에 따라 달려있다고 볼 수 있으므로 궁극적으로 전체적인 프론트엔드 개발을 관통하는 주제라 생각하게 되었고 이를 주제로...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.