Promise译为“承诺”。
用于向执行者(Promise实例)交待一件任务,当任务结束,应如何处理。
使用
new Promise(function(resolve,reject){})
创建promise实例需传入一个函数,函数定义了兑现承诺的逻辑(如何处理)。
函数中的参数定义两个结果的调用:
- 变更任务状态为Fulfilled成功或Rejected失败。
- 将信息作为参数传入,成功信息、失败原因等,使回调方法可以接收:成功被then接收,失败被catch接收。
状态
三种状态:pending(初始状态),fulfilled(resolved)(成功),rejected(失败)
promise对象创建即执行传入的函数,执行函数中的回调即变更promise的状态
打印Promise对象:Promise {<状态>[: 回调传参]}
// pending
var p1 = new Promise(function(resolve, reject){
setTimeout((
resolve("success")
)=>{},500);
});
console.log(p1); // Promise {<pending>}
// resolved/fulfilled
var p2 = new Promise(function(resolve, reject){
resolve("success")
});
console.log(p2); // Promise {<resolved>:"success"}
// rejected
var p3 = new Promise(function(resolve, reject){
resolve("success")
});
console.log(p3); // Promise {<rejected>:"success"}
状态不可逆
状态变更只能是pending->resolved或pending->rejected
状态一旦变更,执行回调不会生效。
var p1 = new Promise(function(resolve, reject){
reject("error"); // 状态变更
reject("error2"); // 未生效
resolve("success"); // 未生效
});
console.log(p1); // Promise {<rejected>:"error"}
p1.catch(err=>{
console.log(err); // error
})
执行顺序特点
- 一旦新建就会立即执行
- 在 JavaScript 事件队列的当前运行完成之前,(resolve, reject)回调函数永远不会被调用。
var p1 = new Promise(function(resolve, reject){
console.log(1);
resolve("success");
console.log(2);
});
console.log(3)
p1.then(data=>{
console.log(4)
})
console.log(5)
setTime(()=>{
console.log(6)
},50);
// 输出顺序:1 2 3 5 4 6
then()
then返回一个新的promise对象
var p1 = new Promise((resolve,reject) => {
setTimeout(()=>{
resolve('success');
},1000);
})
var p2 = p1.then(() => {
throw new Error('this is an error');
})
p2.catch(err=>{console.log(err.message);});
console.log('p1',p1)
console.log('p2',p2)
setTimeout(() => {
console.log('p1',p1)
console.log('p2',p2)
},2000);
/*输出
p1 Promise {<pending>}
p2 Promise {<pending>}
this is an error
p1 Promise {<resolved>:"success">}
p2 Promise {<rejected>:Error:this is an error>}
*/
链式调用
var p1 = new Promise((resolve,reject)=>{
resolve(1);
});
p1.then(value=>{
console.log(value); // 输出:1
return value*2; // 作为下一次调用then回调的参数
}).then(value=>{
console.log(value); // 输出:2
}).then(value=>{ // 上一次then未return,所以参数为undefined
console.log(value); // 输出:undefined
return Promise.resolve('resolve'); // 返回一个状态为resolved的promise,且resolve回调传参为resolve
/* 类似于
return new Promise((resolve,reject)=>{
resolve('resolve');
})
*/
}).then(value=>{
console.log(value); // 输出:resolve
return Promise.reject('reject');
}).then(value=>{ // 由于上一次then返回的是状态为reject的promise,所以直接触发catch
console.log(value); // 不会执行
}).catch(error=>{
console.log(error); // 输出:reject
})
异常
- 创建及操作中的异常,如果定义了catch,就会执行catch回调,否则会抛出错误。
- Promise 对象的错误具有"冒泡"性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个 catch 语句捕获。
- 错误处理完,会继续执行后面的操作,并将catch的return作为下次函数执行的参数。
定义:以下几种定义异常回调在处理创建promise异常时效果一样。注意catch只会处理上一次操作的错误。比如.then(func1,catch1).then(func2,catch2)中func1中的错误由catch2处理,catch1不会触发。
var p1 = new Promise((resolve,reject)=>{
foo.bar();
resolve('success');
});
var catchFunc = err=>{};
p1.then(null, catchFunc);
p1.then(()=>{}, catchFunc);
p1.then(()=>{}).then(()=>{}).catch(catchFunc);
p1.then(()=>{}).then(()=>{},catchFunc);
p1.catch(catchFunc);
触发:
- 执行代码中的异常会触发下次then的第二个函数参数(reject)或catch。例如上例的foo.bar()
- 创建promise时状态变更为rejected时会触发。
- 在创建promise时执行的代码有错误,类似执行了reject(err.message)。若错误在状态变更前,则直接变更promise的状态为rejected,并且如果未定义reject回调(catch)就会抛出错误;若在状态变更后,虽然会中断后面代码的执行,由于状态已变更,则reject(err.message)不会生效,所以也不会抛出错误。
处理:
- 异常处理完,then/catch返回的promise对象会继续执行链式调用
- 若由代码错误导致的异常,导致执行中断
示例1:
var p1 = new Promise((resolve,reject)=>{
foo.bar();
resolve('success');
});
console.log(p1);
/*输出:
Promise {<rejected>: ReferenceError: foo is not defined}
*/
/*抛出错误:
Uncaught (in promise) ReferenceError: foo is not defined
*/
var p1 = new Promise((resolve,reject)=>{
foo.bar();
resolve('success');
});
p1.catch(err=>{
console.log(err.message);
})
console.log(p1);
/*定义了catch,不会抛出错误,输出:
Promise {<rejected>: ReferenceError: foo is not defined}
ReferenceError: foo is not defined
*/
var p1 = new Promise((resolve,reject)=>{
resolve('success');
foo.bar();
});
console.log(p1);
/*状态已变更,后面的异常不会生效,也不会抛出错误。输出:
Promise {<resolved>: "success"}
*/
示例2:
由于创建promise代码中报错,导致两件事情:
- promise状态变更为rejected,类似执行了 reject(err.message)
- 代码中断,未执行后面的代码
var p1 = new Promise((resolve,reject)=>{
foo.bar();
console.log(1);
resolve('success');
console.log(2);
});
p1.then(value=>{
console.log(value);
}).catch(err=>{
console.log(err.message);
console.log(p1);
});
/* 输出
ReferenceError: foo is not defined
Promise {<rejected>: ReferenceError: foo is not defined}
*/
示例3:
错误具有冒泡性质,总会被下一个catch捕获
错误处理完会继续执行后面的then
var p1 = new Promise((resolve,reject)=>{
foo.bar();
resolve('success');
});
p1.then(value=>{
console.log('then1:' + value);
},err=>{
console.log('catch1_error:'+err.message);
return 'catch1_return';
}).catch(err=>{
console.log('catch2_error:'+err.message);
return 'catch2_return';
}).then(value=>{
// then2_foo.bar(); // 若在此处执行错误代码,则会中断后面代码的执行
console.log('then2:' + value);
then2_foo.bar();
}, err=>{
console.log('catch3_error:'+err.message)
}).catch(err=>{
console.log('catch4_error:'+err.message);
});
/* 输出
catch1_error:ReferenceError: foo is not defined
then2:catch1_return
catch4_error:ReferenceError: then2_foo is not defined
*/
then回调异步性
p1.then(
function(value){
console.log('p1 then1');
}
).then(
function(value){
console.log('p1 then2');
}
).then(
function(value){
console.log('p1 then3');
}
);
var p2 = new Promise(function(resolve,reject){
resolve();
});
p2.then(
function(value){
console.log('p2 then1');
}
).then(
function(value){
console.log('p2 then2');
}
).then(
function(value){
console.log('p2 then3');
}
);
/*输出:
p1 then1
p2 then1
p1 then2
p2 then2
p1 then3
p2 then3
*/
拆箱
Promise.resolve(data)
data如果是正常的值(字符串等),Promise.resolve会返回一个以data为参数的状态为resolved的promise对象。
data如果是一个promise对象,就会拆箱获取对这个对象的状态和值(拆箱过程是异步的),最终返回状态为resolved或rejected的对象。
Promise.reject(data)
不会进行拆箱操作,总是会返回一个状态为rejected的promise对象,并将data作为参数调用。
var p0 = new Promise((resolve,reject)=>{
resolve(Promise.resolve('resolve'));
});
var p1 = new Promise((resolve,reject)=>{
resolve(Promise.resolve(p0));
});
var p2 = new Promise((resolve,reject)=>{
resolve(Promise.reject('reject'));
});
var p3 = new Promise((resolve,reject)=>{
reject(Promise.resolve('resolve'));
});
p0.then(value => {
console.log('p0_resolved:' + value);
}, err => {
console.log('p0_rejected:' + err);
})
p1.then(value => {
console.log('p1_resolved:' + value);
}, err => {
console.log('p1_rejected:' + err);
})
p2.then(value => {
console.log('p2_resolved:' + value);
}, err => {
console.log('p2_rejected:' + err);
})
p3.then(value => {
console.log('p3_resolved:' + value);
}, err => {
console.log('p3_rejected:' + err);
})
/*输出:
p3_rejected:[Object:Promise]
p1_resolved:resolve
p2_rejected:reject
*/
p0 p1 p2中resolve需要拆箱,p3中的reject不需要拆箱,所以p3最先输出
p1中Promise.resolve(p0)依然需要拆箱,所以p0 p2先输出
其他
- .then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环
- .then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。
本文深入讲解Promise对象的创建、状态转换、链式调用、异常处理等核心概念,通过实例演示Promise的执行流程与特性,帮助读者掌握Promise的高级用法。
988

被折叠的 条评论
为什么被折叠?



