이 기사는 Promise 객체에 대한 심층 분석을 제공합니다(예제 포함). 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.
JS에서 Asynchronous는 초기에 콜백 함수를 사용하여 구현되었으므로 Asynchronous가 중첩되면 콜백 지옥이 발생하여 코드를 읽고 유지하기가 어려워집니다. 나중에 es6에서는 Promise가 나타나 콜백 문제를 해결했습니다. . 이제 우리는 Promise를 구현하기 위한 코드를 직접 작성하여 Promise의 작동 메커니즘을 깊이 이해하고 앞으로 Promise를 보다 편안하게 사용할 수 있도록 하겠습니다. 시작하기 전에 promise의 공식 홈페이지 promise/A+를 살펴보세요
먼저 promise의 사용법을 살펴보겠습니다
new Promise((resolve,reject)=>{ resolve(1); reject(11); }).then(res=>{ console.log(res); setTimeout(()=>{ return new Promise((resolve,reject)=>{ resolve(2) }) },1000) }).then(res2=>{ console.log(res2); });
콘솔 인쇄
1
...1초 후
2
먼저 위 코드를 분석해 보세요. 그리고 몇 가지 사항을 제시합니다. Question
1. 첫 번째 문단에는 해결과 거부가 모두 있는데 1만 출력됩니다. 이유는 무엇입니까?
2. 그러면 res는 어떻게 해결의 값을 얻나요?
3. 약속은 어떻게 연쇄 호출을 달성하나요?
프로미스에는 상태 머신이라는 개념이 있습니다. 먼저 상태 머신이라는 개념이 있는 이유에 대해 먼저 설명하겠습니다. 프로미스의 상태는 한 방향으로 바뀌기 때문에 보류, 완료, 거부의 세 가지 상태가 있습니다. 그리고 이 세 가지 상태는 보류 중->완료 또는 보류 중->거부라는 두 가지 형태로만 가능합니다. 즉, 완료가 실행된 후에는 거부가 실행되지 않습니다. 이것은 위의 첫 번째 질문을 설명합니다.
특정 구현의 전체 코드를 살펴보겠습니다
const PENDING = 'PENDING'; const FULLFILLED = 'FULLFILLED'; const REJECTED = 'REJECTED'; class Promise{ constructor(fn){ this.status = PENDING;//状态 this.data = undefined;//返回值 this.defercb = [];//回调函数数组 //执行promise的参数函数,并把resolve和reject的this绑定到promise的this fn(this.resolve.bind(this),this.reject.bind(this)); } resolve(value){ if(this.status === PENDING){ //只能pending=>fullfied this.status = FULLFILLED; this.data = value; this.defercb.map(item=>item.onFullFilled()); } } reject(value){ if(this.status === PENDING){ //只能pending=>rejected this.status = REJECTED; this.data = value; this.defercb.map(item=>item.onRejected()); } } then(resolveThen,rejectThen){ //如果没有resolveThen方法,保证值可以穿透到下一个then里有resolveThen的方法中 resolveThen = typeof resolveThen === 'function' ? resolveThen : function(v) {return v}; rejectThen = typeof rejectThen === 'function' ? rejectThen : function(r) {return r}; //返回的都是promise对象,这样就可以保证链式调用了 switch(this.status){ case PENDING: return new Promise((resolve,reject)=>{ const onFullFilled = () => { const result = resolveThen(this.data);//这里调用外部then的resolveThen方法,将值传回去 //如果返回值是promise对象,执行then方法,取它的结果作为新的promise实例的结果,因为this.data会重新赋值 result instanceof Promise && result.then(resolve,reject); } const onRejected = ()=>{ const result = rejectThen(this.data); result instanceof Promise && result.then(resolve,reject); } this.defercb.push({onFullFilled,onRejected}); }); break; case FULLFILLED: return new Promise((resolve,reject)=>{ const result = resolveThen(this.data); result instanceof Promise && result.then(resolve,reject); resolve(result); }) break; case REJECTED: return new Promise((resolve,reject)=>{ const result = rejectThen(this.data); result instanceof Promise && result.then(resolve,reject); reject(result) }) break; } } }
다음 예제를 실행하세요
new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }).then((res2) => { console.log(res2); return new Promise((resolve, reject) => { setTimeout(() => { resolve(2); }, 1000); }); }).then((res3) => { console.log(res3); return new Promise((resolve, reject) => { setTimeout(() => { resolve(3); }, 1000); }); }).then((res4) => { console.log(res4); });
콘솔 인쇄
...1초 후
1
...1초 후
2
...1초 후
3
위 구현에는 문제가 없음을 보여줍니다. 그러나 이벤트 루프의 순서에 또 다른 문제가 있습니다. 예를 들어 다음 코드
new Promise((resolve) => { resolve(); }) .then(() => { console.log('1'); }) .then(() => { console.log('2'); }); console.log('3');를 실행하면 예상대로 3,1,2가 출력되지 않습니다. 3. 그 이유는 Promise가 다음 작업 대기열이 아닌 메인 스레드에 있기 때문입니다. 이 문제를 해결하기 위해 settimeout을 추가할 수 있지만 이는 실행 순서를 더 잘 이해할 수 있도록 하기 위한 것입니다. , 사실 promise는 마이크로 작업에 속하지만 settimeout은 매크로 작업에 속하는데 이는 여전히 다릅니다
위 내용은 Promise 객체에 대한 심층 분석(예제 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!