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()


评论

此博客中的热门博文

docker run和docker container run有什么区别

登录shell和非登录shell区别