promise.then返回结果几种情况
Promise是ES6提出的异步编程的新解决方案,旧方案是单纯的使用回调函数。从语法上看,Promise是一个构造函数,既然是构造函数就可以用来对象的实例化,接受一个函数(执行器函数)作为参数,从功能上看,promise对象用来封装一个异步操作,并可以获取其成功/失败的结果值。获取到结果值后,就可以在回调函数中,对结果值进行处理。
---- 异步操作有 ①fs 文件操作 ②数据库操作 ③Ajax ④定时器
一、promise.then返回结果几种情况
首先实例化一个promise对象。promise对象身上有then方法,可用来指定回调,对成功和失败的结果进行处理。它接受两个回调函数,一个是resolve成功的回调,一个是reject失败的回调。
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功的回调');
// reject('失败的回调');
}, 1000);
});
p.then(value => { }, reason => { });
需要记住的是p.then返回的也是一个promise对象,因此可以进行链式调用。这也是promise可以解决异步编程回调地狱的原因,
重点:then返回的promise对象p1的状态是由then内部回调函数的执行结果来决定的,不取决于p的状态,不取决于你调用的是p的成功或者失败的回调,也就是p1的状态只看回调函数的执行结果。
而回调函数的执行结果有几种情况。如下
1. 如果回调函数的返回结果是 非promise类型的 属性,则then方法返回的promise对象p1的状态为成功fulfilled,同时返回的结果就是promise对象p1成功的值11112222,如下图。需要注意的是,如果你不写return,我们知道函数内部如果不写return默认返回结果是undefined,又undefined也是非promise类型,所以p1状态还是成功fulfilled,返回的promise成功值为undefined。
const p1 = p.then(value => { //接受p成功的回调
return '11112222'
}, reason => { });
console.log(p1); //输出p1这个promise对象
const p1 = p.then(value => { }, reason => { //接受p失败的回调
return '33334444'
});
console.log(p1); //
此时p1的状态还是fulfilled,证明只和回调函数的返回结果有关系
2.如果回调函数的返回结果是promise对象,则p1的状态就取决于return返回的这个promise对象内部的状态,内部为resolve, 则p1状态为fulfilled,内部为reject,则p1状态为rejected
const p1 = p.then(value => {
return new Promise((resolve, reject) => {
reject('出错了')
})
}, reason => { });
console.log(p1); //结果为rejected
3.第三种情况为抛出错误,则p1状态为rejected,返回的结果就是你抛出的值
const p1 = p.then(value => {
// throw new Error('出错了');
throw '出错了'; //没有return,直接抛出错误
}, reason => { });
console.log(p1);
二、改变promise对象的状态(非then方法中)
实例化一个promise对象,接受一个函数类型的值,里面可以封装异步操作。状态的改变只有两条路,进行中pending变为成功resolved,进行中变为失败rejected,而且只会改变一次,不可能从成功变为失败或者失败变为成功。
只有三种方法改变promise对象的状态,resolve/ reject/ throw抛出错误,如果你在promise对象中不去改变他的状态,那么他的状态永远都是pending,也不会去执行回调函数。
let p = new Promise((resolve, reject) => {
resolve('成功数据'); //状态变为 成功resolved
reject('失败数据'); //状态变为 失败rejected
throw '报错' //状态变为 失败rejected
throw new Error('123'); //状态变为 失败rejected
})
注意:return并不能改变他的状态,这不是在then方法中,then方法有自己的一套东西。
三、注意点
1、promise对象里面的代码是同步执行的,只是回调函数才是异步执行的,因为你不改变状态就不会去执行回调。而且状态改变后,后续的代码继续执行。
let p = new Promise((resolve, reject) => {
console.log(1);
reject('error');
console.log(2);
});
console.log(3);
p.catch(reason => {
console.log(reason); //最后输出 ‘error’
});
console.log(4);
结果:1 2 3 4 error
2、指定多个回调都会被执行
let p = new Promise((resolve, reject) => {
resolve('OK');
});
p.then(value => {
console.log(value);
});
p.then(value => {
console.log(value);
});
输出: ok ok
3、假设你的promise对象,状态变为失败,但是你的then每次只写成功的回调,那就找不到失败的回调,那么他会顺着链一直往下传递,直到找到失败的回调。这就是异常穿透。同理,你的promise对象,状态变为成功,但是你的链只写catch,那就找不到成功的回调,那么他会顺着链一直往下传递,直到找到成功的回调。
三、async/await
async/await 是ES7提出的基于Promise的解决异步的最终方案。
1、async
async也是一个函数,他和一般的函数不同,他的返回结果是一个promise对象,而且该promise对象的结果是由async函数执行的返回值来决定的,这一点和promise的then的回调函数很像,都是通过返回值来决定状态和结果的。
既然返回promise就可以使用promise的方法,then,all,race
async function main(){
// 1、 return非promise类型的数据
return 123;
// 2、 return的是promise对象
return new Promise((resolve,reject)=>{
resolve('success')
// reject('error')
})
// 3、抛出异常
throw '异常'
}
console.log(main()) //返回promise对象
main().then(data=>{
console.log(data);
},reason=>{
console.log(reason);
})
2、await + 表达式
await必须写在async函数当中,但是async函数中可以没有await。await可以理解为等待,且等到取到值后语句才会往下执行。await其实说白了就是对promise对象的成功结果进行获取,如果失败就通过catch获取失败的结果。
await的右侧的表达式一般都是promise对象,但也可以是其他值
一、如果表达式是promise对象并且状态为成功,那么await将返回的是这个promise对象成功的值;
二、如果表达式是promise对象,并且它失败了,那么就要通过try,catch进行捕获错误,不捕获错误那么后面代码无法执行。
三、如果不是Promise对象,把这个非promise的东西当做await表达式的结果,如字符串数字等。
async function main(){
let p1 = new Promise((resolve,reject)=>{
resolve('success')
})
let p2 = new Promise((resolve,reject)=>{
reject('error')
})
// 1、右侧为promise情况,常用
let res1 = await p1;
console.log(res1); // success
// 2、右侧为promise情况,并且失败了,失败了没有通过 trycatch 捕获,那后面代码就不会执行了
try {
let res2 = await p2;
} catch (e) {
console.log(e);
}
// 3、右侧为非promise类型的数据
let res3 = await 123;
console.log(res3); // 123
}
main()
评论
发表评论