Promise
- Promise 是 ES6 提供的类,是异步编程的一种解决方案,不是指将异步转换为同步的方法,目的是更加优雅地书写复杂的异步任务
优点
1. 对象状态不受外界影响
- 三个状态
pending:进行中
fulfilled:已成功
reject:已失败
Promise即承诺的意思,承诺什么呢?即只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
2. 一旦改变状态,就不会再变,并且任何时候都可以得到这个结果
- Promise状态的改变只有两种情况:pending到fulfilled与pending到reject
- 只要这两种情况发生,状态就不会再变了,会一直保持这个结果,这时就称为resolved(已定型),并且可以通过对Promise对象添加回调函数得到这个结果(与事件不同,事件错过再去监听是得不到任何结果的)
缺点
1. 无法取消Promise
2. 错误判别
- 如果不设置回调函数,Promise内部抛出的错误,不会反映到外部
3. 不可预知状态
- 当处于pending状态时,无法得知目前进展到哪一个状态,是刚刚开始还是即将完成
一、构造 Promise
new Promise(function (resolve, reject) {
});
- Promise 构造函数只有一个参数,是一个函数,这个函数在构造之后会直接被异步运行,所以我们称之为起始函数,起始函数包含两个参数 resolve 和 reject,当 Promise 被构造时,起始函数会被异步执行
- resolve 和 reject 都是函数(JavaScript引擎提供的,不用自己部署),其中调用 resolve 代表一切正常,即在异步函数操作成功的时候调用,并将异步操作的结果作为参数传递出去,reject 是出现异常时所调用的,即在异步操作失败的时候调用,并将异步操作报出的错误作为参数传递出去
- resolve() 中可以放置一个参数用于向下一个 then 传递一个值,then 中的函数也可以返回一个值传递给 then,但是,如果 then 中返回的是一个 Promise 对象,那么下一个 then 将相当于对这个返回的 Promise 进行操作
- reject() 参数中一般会传递一个异常给之后的 catch 函数用于处理异常
- resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列
- resolve 和 reject 并不能够使起始函数停止运行,应该使用 return
二、Promise 方法
1. then()
- then() 可以将参数中的函数添加到当前 Promise 的正常执行序列
- then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列
- 如何中断then 块:then 块默认会向下顺序执行,return 是不能中断的,可以通过 throw 来跳转至 catch 实现中断
- then 块可以多次使用,但是 catch 块只会执行第一个,除非 catch 块里有异常,所以最好只安排一个 catch 和 finally 块
- 当我们需要调用一个异步任务的时候,需要再写一个 then 而不是在当前的 then 接着编程
2. catch()
- catch() 则是设定 Promise 的异常处理序列
3. finally()
- finally() 是在 Promise 执行的最后一定会执行的序列
- then、catch 和 finally 序列可以颠倒顺序,但不建议这样做,最好按 then-catch-finally 的顺序编写程序
三、函数瀑布
- 用 “函数瀑布” 实现的程序无论是维护还是异常处理都是一件特别繁琐的事情,而且会让缩进格式变得非常冗余
- 举例
setTimeout(function () {
console.log("l");
setTimeout(function () {
console.log("z");
setTimeout(function () {
console.log("j");
}, 3000);
}, 2000);
}, 1000);
四、使用Promise改进
- 有了Promise对象,我们就可以将异步操作以同步操作的流程表达出来,从而避免层层嵌套的回调函数,此外,Promise对象提供统一的接口,使得控制异步操作更加容易
- 初步改进
new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("l");
resolve();
}, 1000);
}).then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("z");
resolve();
}, 2000);
});
}).then(function () {
setTimeout(function () {
console.log("j");
}, 3000);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>promiseTest</title>
<script>
function print(delay, message) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(message);
resolve();
}, delay);
});
}
print(1000,"m").then(function (){
return print(2000,"a");
}).then(function () {
print(3000,"y");
})
</script>
</head>
<body>
</body>
</html>
五、异步函数(async function)
- 异步函数是通过事件循环(event loop) 异步执行的函数,返回一个隐式的 Promise 作为其结果
- 语法
async function name([param[, param[, ... param]]]) {
statements }
1. 使用异步函数优化实例
async function asyncFunc() {
await print(1000, "m");
await print(4000, "a");
await print(3000, "y");
}
asyncFunc();
- 异步函数 async function 中可以使用 await 指令,await 指令后必须跟着一个 Promise,异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行,即await 指令暂停异步函数的执行,并等待 Promise的执行结果返回,结果返回后就恢复异步函数的执行,并且await 指令只在异步函数(async functions)内有效,如果在异步函数外使用它,会抛出语法错误
2. try-catch 块处理异常
- 返回一个promise对象,并返回异步函数的值(如果异步函数是resolve则返回resolve的值;如果抛出异常,则抛出reject在异步函数中声明的异常)
async function testA(){
try {
await new Promise(function (resolve, reject) {
reject("may");
})
} catch (e) {
console.log(e);
}
}
testA();
async function test(){
let t = await new Promise(function (resolve, reject) {
resolve("day");
})
console.log(t);
}
test();