Promise及其应用
promise与异步编程
Promise是异步编程的一种解决方案,比传统方法(回调函数与事件)更合理、更强大。
promise作用
- promise是一个容器,里面保存着未来才会结束的事情的结果,这个事情通常是一个异步操作,例如:老师在课堂上布置了考试内容,考试时间20分钟,20分钟以后老师发下答案,让同学们在课后核对答案,老师则继续讲课,promise就相当于学生课后核对答案这个事情的结果,与主线程(老师讲课)毫不相干。
- 在语法上,promise是一个对象,可以获取异步操作的消息。
- promise提供统一的API,各种异步操作都可以用同样的方法进行处理。
promise特点
- 对象状态不受外界影响。 Promise对象代表一个异步操作,有三种状态:
- pending(进行中)
- fulfilled(已成功)
- rejected(已失败)
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
- 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
promise缺点
- 无法取消promise,一旦新建它就会立即执行,无法中途取消
- 如果不设置回调函数,promise内部抛出的错误不会反应到外部
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
promise基本用法
示例
console.log("a");
setTimeout(() => console.log("b"));
let p = new Promise((resolve, reject) => {
resolve();
console.log("c");
}).then(() => {
console.log("d");
});
console.log("e");
首先此段代码会输出a。来到了seTimeout(),seTimeout定时器要等时间到才会触发事件进入宏任务,所以b输出会在最后执行。resolve作为一个执行器函数,作为同步代码执行,会立即执行,所以c的输出会放在宏任务,相比then,会先执行,输出c。随后then方法不会立即输出d,它会将回调注册到promise的fulfilled状态,和setimeout相似,fulfilled在then里面会放在微任务队列,后面执行。所以此时要等脚本执行完,先输出e,再输出d。等所有宏任务执行完以后,setimeout函数触发事件进入宏任务,最后输出b。所以此上函数输出顺序为acedb。
resolve()与reject()
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
const promise = new Promise(function (resolve, reject) {
//...do something
if (/*异步操作成功*/) {
resolve(value);
} else {
reject(error);
}
- resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 fulfilled),在异步操作成功时调用,并将异步操作成功的结果,作为参数传递出去。
- reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
then()方法
promise实例生成后,可以使用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value){
//value
}, function(error){
//error
});
then方法可以接受两个回调函数作为参数
- 第一个回调函数:promise对象的状态变为fulfilled时调用。
- 第二个回调函数:promise对象的状态变为rejected时调用。
- 注意第二个函数可选,不一定非要提供。
注: promise新建以后会立即执行,首先输出的是promise,then方法指定的回调函数将在当前脚本所有同步任务执行完才会执行。
resolve()与reject()方法
promise.resolved()方法
- 返回一个具有定值的promise对象
- 如果传入的参数是一个promise实例,则将该实例直接返回;否则会创建一个新的promise对象,将传入的参数作为promise对象的fulfilled值。
promise.reject()方法
用于返回一个rejected状态的promise实例,但是不常用。
原因:状态已经被置为rejected,rejected函数只能用onrejected函数执行,所以只能用catch。
Promise.reject(new Error("a error"))
.catch((err)=>{
console.log(err.message);
return "done";
})
.then((value)=>{
console.log(value);
});
注:rejected和resolve为构造函数方法,catch和then为实例方法 调用resolve和reject之后,promise的使命已经完成,后续操作都会放进then方法里面。
链式调用
promise实例可以链式的使用then()调用,并且可以一直调用。
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
let t = true;
if (t) {
resolve("success");
} else {
reject("failed");
}
}, 1000);
});
promise1.then((r) => {
console.log(r);
return r + "1";
}).then((r) => {
console.log(r);
return r + "2";
}).then((r) => {
console.log(r);
});
以上代码then方法的调用中,每一个r都依赖于上一个r。
多个Promise一起调用
Promis.all()
当需要将多个Promise任务一起执行时,可以使用Promise.all( )方法。 Promise.all( )执行完毕的结果是所有输出结果的所组成的数组。
var p1 = new Promise((res, rej) => {
setTimeout(() => {
res("p1");
}, 1000);
});
var p2 = new Promise((res, rej) => {
setTimeout(() => {
res("p2");
}, 2000);
});
var p3 = new Promise((res, rej) => {
setTimeout(() => {
res("p3");
}, 3000);
});
Promise.all([p1, p2, p3]).then((r) => {
console.log(r);
}).catch((err) => console.log(err.messsage));
注意:只要有一个失败,也就是说只要有一个rej,都会返回失败,返回失败则执行catch。 如果执行成功,则是按照数组的顺序输出,而不是按照时间长短来输出。
Promise.race(iterable)方法(谁先完成)
以下方示例
- iterable为包含了多个promise数组。
- 该方法返回一个 promise。
- 一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。
执行此代码时promise3的错误会直接抛给浏览器,因为跑的最快的发生错误,catch会执行。但是如果执行到then时的结果为true,但是也会报错,因为promise3的错误未处理。
async函数
async作用与用法
ES2017引入了async函数。
async function testAsync() {
return "hello async";
}
console.log(testAsync());
testAsync().then((r) => {
console.log(r);
});
async函数返回的Promise对象会运行执行(resolve)异步函数的返回结果,会把返回值传递给Promise.resolve(),如果异步函数抛出异常的话会运行拒绝(reject)。
await指令
await作用与用法
异步函数可以包含await指令,该指令会暂停异步函数的执行,并等待Promise执行,然后继续执行异步函数,并返回结果。 示例:
function testAsync() {
//只有返回值、没有返回Promise的函数
return "hello async";
}
function testPromise() {
//返回Promise的函数
return new Promise((resolve) => {
resolve("hello Promise");
});
}
async function test() {
var Async_1 = await testAsync();
var Promise_1 = await testPromise().then();
console.log(Async_1);
console.log(Promise_1);
}
test();
综合async、await分析
async 函数是使用async关键字声明的函数。async 函数是 AsyncFunction 构造函数的实例,并且其中允许使用 await 关键字。async 和 await 关键字让我们可以用一种更简洁的方式写出基于 Promise的异步行为,而无需刻意地链式调用 promise。