文章目录
一、异步编程和promise的关系
Promise是异步编程的解决方案之一(异步编程中数据传递或回调嵌套的问题),Promise实际上是一个许诺器,它里面通常放的是将来要执行的异步代码,这些代码执行完成后会有两种结果:成功或失败
Promise的特点:
1、Promise内部的代码是以同步方式执行的;
2、通过Promise对象调用多个then()方法,但调用多个catch()没有意义;
3、在then()方法中可以通过return返回具体的值或Promise对象给后面的then()传递参数值;
二、promise的三种状态
Promise有三种状态:pending(初始状态)、success/fullfill(成功状态)、reject(失败状态),当我们在Promise内部调用了成功时的回调方法resolve()时则把Promise的pending(初始状态)转换成success/fullfill(成功状态),当我们在Promise内部调用了失败时的回调方法reject()时则把Promise的pending(初始状态)转换成reject(失败状态)。
三、promise的作用和用法
1.promise的作用
1.可以避免多层异步调用嵌套问题(回调地狱)
2.Promise 对象提供了简洁的API,使得控制异步操作更加容易(js执行机制导致的异步问题)
2.promise的用法
1.promise的实例方法
①then()得到异步任务的正确结果
②catch()获取异常信息
③finally()成功与否都会执行(尚且不是正式标准)
注意:then方法可以接受两个函数,第一个函数为promise状态为成功的回调函数,第二个函数为promise状态为失败的回调函数(可以不写,一般用catch方法捕获promise状态为失败的异常信息)
2.promise的对象方法(p1,p2,p3为promise的实例对象)
①Promise.all()并发处理多个异步任务,所有任务都执行完成才能得到结果
Promise.all( [p1,p2,p3] ) .then ( (result) => {console.log (result)})
②Promise.race()并发处理多个异步任务,只要有一个任务完成就能得到结果
Promise.race ( [p1,p2,p3] ).then ( (result)=>{
console. log (result)})
4.promise在实际环境下的作用
1.在Promise对象的构造函数中,将一个函数作为第一个参数。
2.而Promise对象的构造函数的第一个参数中的这个函数,就是用来处理Promise的状态变化,这个函数的第一个参数表示promise的状态为成功,第二个参数表示promise的状态为失败,这两个参数(名字可以自己命名)都为一个函数,他们的作用分别是将promise状态修改为resolved(成功)和rejected(失败)。
<script>
function fn(flag) {
//构造函数
return new Promise(function(resolve, reject) {
if (flag === true) {
resolve('promise状态为成功!')
};
if (flag === false) {
reject('promise状态失败!')
};
})
}
console.log(fn(true));
</script>
3. Promise对象中的then方法,可以接收构造函数中处理的状态变化,并分别对应执行。then方法有2个函数参数,第一个函数接收resolved(promise状态为成功)的执行,第二个函数接收reject(promise状态为失败)的执行。
<script>
function fn(flag) {
return new Promise(function(resolve, reject) {
if (flag === true) {
resolve('promise状态为成功!')
};
if (flag === false) {
reject('promise状态失败!')
};
}).then(function(res) {
console.log(res);
},
function(err) {
console.log(err);
})
}
fn(true)
fn(false)
</script>
4.promise的状态只能从 未完成->完成, 未完成->失败 且状态不可逆转。
promise的异步结果,只能在完成状态时才能返回,而且我们在开发中是根据结果来选择来选择状态的,然后根据状态来选择是否执行then()。
实例化的Promise内部会立即执行,then方法中的异步回调函数会在脚本中所有同步任务完成时才会执行。因此,promise的异步回调结果最后输出。示例代码如下:
var promise = new Promise(function(resolve, reject) {
console.log('Promise instance');
resolve();
});
promise.then(function() {
console.log('resolved result');
});
for(var i=0;i<100;i++) {
console.log(i);
/*
Promise instance
1
2
3
...
99
100
resolved result
*/
5.Promise.then()方法
①then()函数返回的实际也是一个Promise对象(无论函数内部返回什么类型的数据,函数都会进行加工返回一个promise对象)
<script>
function fn(flag) {
return new Promise(function(resolve, reject) {
if (flag === true) {
resolve('promise状态为成功!')
};
if (flag === false) {
reject('promise状态失败!')
};
})
}
console.log(fn(true).then());
</script>
②then()函数内部返回为普通值(非Promise类型的属性),返回的普通值会直接传递给下一个then,通过then参数中函数的参数接收该值。
这时then()函数返回的Promise对象状态为成功(resloved),then()函数的返回值为对象的成功值,如return 123,返回的Promise对象值为123,如果没有返回值,是undefined
<script>
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据');
})
});
let result = p.then(value => {
return 123;
}, reason => {
console.log(reason)
})
console.log(result);
result.then(function(res) {
console.log(res);
})
</script>
③ 当then()函数内部返回的是Promise类型的对象时,then()函数的返回的Promise对象的状态值为这个Promise对象的状态值,成功值也是如此,返回的该promise对象会调用下一个then方法。
<script>
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据');
})
});
let result = p.then(value => {
return new Promise((resolve, reject) => {
resolve('ok')
})
}, reason => {
console.log(reason)
})
console.log(result);
result.then(function(res) {
console.log(res);
})
</script>
④当then()函数内部果抛出异常,则then()函数的返回值状态也是rejected
<script>
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据');
})
});
let result = p.then(value => {
throw 123
}, reason => {
console.log(reason)
})
console.log(result);
</script>
6.Promise.catch()方法
①catch()函数只有一个回调函数,意味着如果Promise对象状态为失败就会调用catch()方法并且调用回调
//catch()函数只有一个回调函数,意味着如果Promise对象状态为失败就会调用catch()方法并且调用回调函数
<script>
const p = new Promise((resolve, reject) => {
setTimeout(()=>{
reject('出错啦')
},1000)
})
p.catch(reason => {
console.log(reason)
})
</script>
五、async/await的作用和用法
async
用于声明异步函数,返回值为一个 Promise 对象,它以类似 同步 的方式来写异步方法,语法与声明函数类似,例如:
async function fn() {
console.log('Hello world!');
}
console.log(fn().constructor); // Promise()
// 这里证明其返回值为一个 Promise 对象;
返回值
也许这里会有疑问,返回值是 Promise 对象,那么函数本身定义的返回值跑到哪里去了呢?其实,熟悉 Promise 的就知道其异步结果是通过 .then() 或者 .catch() 方法来获取并进行进一步处理的,这样一个道理,定义的异步函数中的返回值会当成 resolve 状态来处理,一般用 .then() 方法处理,而如果定义的异步函数抛出错误,例如变量未定义,则会被当做 reject 状态来处理,一般使用 .catch() 方法来处理;
// 使用 .then() 的情况
async function fn1() {
return 'Hello world!';
}
fn1().then(function(res) {
console.log(res);
});
// Hello world!
// 使用 .catch() 的情况
async function fn2() {
console.log(aaa); // 这里的变量 aaa 未定义,为了制造错误
}
fn2().catch(function(error) {
console.log(error);
});
// ReferenceError: aaa is not defined
假如是既有返回值,又有错误的话,来看看结果如何:
async function fn3(){
console.log(aaa); // aaa 依然未定义;
return 'Hello world!';
}
fn3().then(function(res){
console.log(res);
}).catch(function(error){
console.log(error);
});
// ReferenceError: aaa is not defined
结果证明只会执行 reject 状态的情况下的语句,忽略了 resolve 时的代码
await
用法顾名思义,有 等待 的意思,语法为:
var value = await myPromise();
所谓 等待 其实就是指暂停当前 async function 内部语句的执行,等待后面的 myPromise() 处理完返回结果后,继续执行 async function 函数内部的剩余语句;myPromise() 是一个 Promise对象,而自定义的变量 value 则用于获取 Promise 对象返回的 resolve 状态值;
用法
值得 注意 的是,await 必须在 async function 内使用,否则会提示语法错误;如果 await 后面跟的是其他值,则直接返回该值:
async function fn() {
console.log(1);
var result = await new Promise(function(resolve, reject) {
setTimeout(function(){
resolve(2);
}, 2000);
});
console.log(result);
console.log(3);
console.log(await 4); // 4 会被直接返回
}
fn();
// 1
// 2 (2 秒后输出)
// 3
// 4
如果不用获取返回值,也可以直接执行语句:
async function fn() {
console.log(1);
await new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(2);
resolve(0);
}, 2000);
});
console.log(3);
}
fn();
// 1
// 2 (2 秒后)
// 3
返回结果
如之前所说,await 会等到后面的 Promise 返回结果 后才会执行 async 函数后面剩下的语句,也就是说如果 Promise 不返回结果(如 resolve 或 reject),后面的代码就不会执行,例如:
async function fn() {
console.log(1);
await new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(2);
}, 2000);
});
console.log(3);
}
fn();
// 1
// 2 (2 秒后输出,并且后面不会继续输出 3)
这里可以理解为函数会一直等待 await 返回结果(resolve / reject)才会执行剩下的语句,没有返回结果就会一直等下去,也就一直等不到剩下的语句执行了(还挺痴情-_-);
如果 await 后面的 Promise 返回一个 reject 状态的结果的话,则会被当成错误在后台抛出,例如:
async function fn() {
console.log(1);
var result = await new Promise(function(resolve, reject) {
setTimeout(function() {
reject(2);
}, 2000);
});
console.log(3);
}
fn();
// 1
// Uncaught (in promise) 2 (2 秒后输出)
如上,2 秒后会抛出出错误,并且 3 这个数并没有被输出,说明后面的执行也被忽略了;