深入理解ES6 Promise:从原理到实战的八步解析

作者:异步漫步时间:2026-10-22 06:26:30浏览:538

本文通过八段代码深入解析ES6 Promise的核心机制。内容涵盖Promise的立即执行特性、三种状态(Pending、Resolved、Rejected)及其不可逆性、链式调用的返回值处理规则、then回调的异步执行顺序,以及Promise.resolve与reject在拆箱行为上的关键差异,帮助开发者彻底掌握异步编程的最佳实践。

ES6 Promise核心机制解析

前言

ES6标准引入了Promise概念,旨在优化回调函数的使用体验,解决深层嵌套导致的代码可读性差和结构混乱问题。JavaScript社区推崇链式调用风格,Promise正是为此而生。本文将通过八个具体代码示例,系统性地解析Promise的工作机制,帮助读者全面掌握这一核心特性。

Promise的立即执行特性

1. Promise的立即执行特性


var p = new Promise(function(resolve, reject){
 console.log("create a promise");
 resolve("success");
});

console.log("after new Promise");

p.then(function(value){
 console.log(value);
});

控制台输出:


"create a promise"
"after new Promise"
"success"

Promise实例在创建(new)时,其构造函数内的回调函数会立即同步执行,无论内部逻辑是同步还是异步。常见误区是认为只有调用then方法时回调才会执行,这是错误的。因此,代码中create a promise的输出顺序先于after new Promise。

Promise的三种状态

2. Promise的三种状态


var p1 = new Promise(function(resolve,reject){
 resolve(1);
});
var p2 = new Promise(function(resolve,reject){
 setTimeout(function(){
 resolve(2); 
 }, 500); 
});
var p3 = new Promise(function(resolve,reject){
 setTimeout(function(){
 reject(3); 
 }, 500); 
});

console.log(p1);
console.log(p2);
console.log(p3);
setTimeout(function(){
 console.log(p2);
}, 1000);
setTimeout(function(){
 console.log(p3);
}, 1000);

p1.then(function(value){
 console.log(value);
});
p2.then(function(value){
 console.log(value);
});
p3.catch(function(err){
 console.log(err);
});

控制台输出:


Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
1
2
3
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 2}
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: 3}

Promise内部实现为状态机,包含三种状态:pending(进行中)、resolved(已成功)和rejected(已失败)。初始创建时处于pending状态;若执行resolve,则转为resolved;若执行reject,则转为rejected。

p2和p3刚创建时均为pending状态,但p1为何直接显示为resolved?因为p1的构造函数内执行的是同步代码,resolve在创建瞬间即被调用,故后续输出显示其状态为resolved。通过setTimeout延迟1秒后,p2和p3已完成执行,状态分别变为resolved和rejected。

Promise状态的不可逆性

3. Promise状态的不可逆性


var p1 = new Promise(function(resolve, reject){
 resolve("success1");
 resolve("success2");
});

var p2 = new Promise(function(resolve, reject){
 resolve("success");
 reject("reject");
});

p1.then(function(value){
 console.log(value);
});

p2.then(function(value){
 console.log(value);
});

控制台输出:


"success1"
"success"

一旦Promise状态变为resolved或rejected,其状态和值即固定,后续再调用resolve或reject均无效。因此,p1中resolve("success2")无法将值修改为success2,p2中reject("reject")也无法将状态由resolved改为rejected。

链式调用机制

4. 链式调用机制


var p = new Promise(function(resolve, reject){
 resolve(1);
});
p.then(function(value){ //第一个then
 console.log(value);
 return value*2;
}).then(function(value){ //第二个then
 console.log(value);
}).then(function(value){ //第三个then
 console.log(value);
 return Promise.resolve('resolve'); 
}).then(function(value){ //第四个then
 console.log(value);
 return Promise.reject('reject');
}).then(function(value){ //第五个then
 console.log('resolve: '+ value);
}, function(err){
 console.log('reject: ' + err);
})

控制台输出:


1
2
undefined
"resolve"
"reject: reject"

Promise的then方法返回一个新的Promise实例,支持链式调用。then接收两个回调:成功回调和失败回调,二者仅有一个会被触发,其返回值决定新Promise的状态和值。返回值可能为以下三种情况之一:

  • 返回同步值或undefined(无有效返回值时默认为undefined),then返回resolved状态的Promise,值为该返回值。
  • 返回另一个Promise,then根据该Promise的状态和值创建并返回新的Promise。
  • 抛出同步异常,then返回rejected状态的Promise,值为该异常。

基于上述规则,第一个then返回值为2(1*2)、状态为resolved的Promise,故第二个then输出2。第二个then无返回值,返回默认undefined,第三个then输出undefined。第三个then返回resolved状态的Promise,第四个then返回rejected状态的Promise,分别由第四个then的成功回调和第五个then的失败回调处理。

then回调的异步性

5. Promise then() 回调的异步性


var p = new Promise(function(resolve, reject){
 resolve("success");
});

p.then(function(value){
 console.log(value);
});

console.log("which one is called first ?");

控制台输出:


"which one is called first ?"
"success"

Promise构造函数内的回调是同步执行的,但then中的回调函数是异步执行的。因此,"success"会在后续输出。

Promise中的异常处理

6. Promise中的异常处理


var p1 = new Promise( function(resolve,reject){
 foo.bar();
 resolve( 1 ); 
});

p1.then(
 function(value){
 console.log('p1 then value: ' + value);
 },
 function(err){
 console.log('p1 then err: ' + err);
 }
).then(
 function(value){
 console.log('p1 then then value: '+value);
 },
 function(err){
 console.log('p1 then then err: ' + err);
 }
);

var p2 = new Promise(function(resolve,reject){
 resolve( 2 ); 
});

p2.then(
 function(value){
 console.log('p2 then value: ' + value);
 foo.bar();
 }, 
 function(err){
 console.log('p2 then err: ' + err);
 }
).then(
 function(value){
 console.log('p2 then then value: ' + value);
 },
 function(err){
 console.log('p2 then then err: ' + err);
 return 1;
 }
).then(
 function(value){
 console.log('p2 then then then value: ' + value);
 },
 function(err){
 console.log('p2 then then then err: ' + err);
 }
);

控制台输出:


p1 then err: ReferenceError: foo is not defined
p2 then value: 2
p1 then then value: undefined
p2 then then err: ReferenceError: foo is not defined
p2 then then then value: 1

Promise中的异常由then的第二个回调(失败回调)处理,异常信息作为Promise的值。异常处理后,后续Promise恢复正常,由成功回调处理。需注意,p1和p2的多级then回调交替执行,这源于then回调的异步特性。

Promise.resolve()方法

7. Promise.resolve()方法


var p1 = Promise.resolve( 1 );
var p2 = Promise.resolve( p1 );
var p3 = new Promise(function(resolve, reject){
 resolve(1);
});
var p4 = new Promise(function(resolve, reject){
 resolve(p1);
});

console.log(p1 === p2); 
console.log(p1 === p3);
console.log(p1 === p4);
console.log(p3 === p4);

p4.then(function(value){
 console.log('p4=' + value);
});

p2.then(function(value){
 console.log('p2=' + value);
})

p1.then(function(value){
 console.log('p1=' + value);
})

控制台输出:


true
false
false
false
p2=1
p1=1
p4=1

Promise.resolve(...)可接收普通值或Promise对象。若为普通值,返回resolved状态的Promise,值为该参数;若为Promise对象,直接返回该对象,故p1 === p2。但通过new创建的Promise均为新对象,后续比较结果为false。p4的then最先调用却最后输出,是因为其resolve参数为Promise对象p1,resolve会对p1进行“拆箱”获取状态和值,该过程是异步的,详见下一节。

resolve与reject的差异

8. resolve与reject的差异


var p1 = new Promise(function(resolve, reject){
 resolve(Promise.resolve('resolve'));
});

var p2 = new Promise(function(resolve, reject){
 resolve(Promise.reject('reject'));
});

var p3 = new Promise(function(resolve, reject){
 reject(Promise.resolve('resolve'));
});

p1.then(
 function fulfilled(value){
 console.log('fulfilled: ' + value);
 }, 
 function rejected(err){
 console.log('rejected: ' + err);
 }
);

p2.then(
 function fulfilled(value){
 console.log('fulfilled: ' + value);
 }, 
 function rejected(err){
 console.log('rejected: ' + err);
 }
);

p3.then(
 function fulfilled(value){
 console.log('fulfilled: ' + value);
 }, 
 function rejected(err){
 console.log('rejected: ' + err);
 }
);

控制台输出:


p3 rejected: [object Promise]
p1 fulfilled: resolve
p2 rejected: reject

Promise回调中的resolve参数具备“拆箱”能力:若参数为Promise对象,resolve会异步获取其状态和值。p1拆箱后状态为resolved,触发fulfilled回调;p2拆箱后状态为rejected,触发rejected回调。而reject参数不具备拆箱能力,其参数直接传递给then的失败回调。因此,即使p3的reject接收了resolved状态的Promise,then仍调用rejected回调,且参数为reject接收到的Promise对象。

总结

本文全面解析了ES6 Promise的核心机制,涵盖状态管理、链式调用、异步处理及关键方法差异。希望这些内容能协助读者深入理解并应用Promise,提升JavaScript异步编程能力。如有疑问,欢迎留言交流,感谢支持。

作者最新文章