Promise
中文为承诺,异步编程的新解决方案(旧的解决方案是回调函数),从语法上来说就是一个构造函数,用来封装异步任务,解决回调地狱的问题,封装一个异步操作,用来获取成功或者失败的结果的值
旧的解决方案实例:
变量.use((param1, param2) => {
}, param);
// 定时器也是回调
setInterval(() => {
}, 33333)
其中第一个参数就是一个回调函数
优点:
- 支持链式操作
- 解决了回调地狱
- 回调地狱是指一个回调函数中嵌套着另外的异步任务
- 不便于阅读
- 不便于异常错误处理
- 回调地狱是指一个回调函数中嵌套着另外的异步任务
- 支持链式调用
setTimeout(() => {
console.log("hello")
}, 1000);
基本形式为:
const p = new Promise((resolve, reject) => {
if(成功的条件) {
// 将状态置为成功
resolve();
} else {
// 将状态置为失败
reject();
}
});
p.then(() => {
console.log("成功的回调");
}, () => {
console.log("失败的回调")
});
// 代码可以精简为:
new Promise((resolve, reject) => {
if(成功的条件) {
resolve();
} else {
// 失败
reject();
}
}).then(() => {
console.log("成功的回调");
}, () => {
console.log("失败的回调")
});
-
当成功时调用
resolve
,中文为解决,失败时调用reject
-
可以执行多个回调:
const p = new Promise((resolve, reject) => { let number = Number.parseInt(Math.random() * 10); console.log(number); if (number % 2 === 0) { resolve(number); reject("失败水水水水") } else { reject("---失败了"); } }); p.then((n) => { console.log("成功的回调" + n); }, (n) => { console.log("失败的回调" + n) }); p.then((n) => { console.log("第二个成功回调") }, reason => { console.log("第二个失败回调") })
7 失败的回调---失败了 第二个失败回调 7 失败的回调---失败了 第二个失败回调
获取结果
成功或者失败也可以将结果传进去
new Promise((resolve, reject) => {
if(成功的条件) {
resolve(值);
} else {
// 失败
reject(值);
}
}).then((res) => {
console.log("成功的回调" + res);
}, (res) => {
console.log("失败的回调" + res)
});
同时获取到执行的结果值
对象的属性状态 promiseStatus
是指实例对象中的一个属性,状态包括:
pending
,ˈpendiNG
中文为待办的,初始的状态resolve
或者fulfilled
,代表成功reject
,代表失败
只能由初始状态变换为成功或者失败状态,不能由成功变为失败,失败变为成功,状态只能改变一次
状态的改变
pending ->resolve
、pending -> reject
、throw 错误
try {
throw "错误";
} catch (e) {
console.log("异常" + e);
} finally {
console.log("都会执行的")
}
对象的结果值属性 promiseResult
存储的是对象成功或者失败的结果,只能由resolve()
和reject()
进行修改
工作流程
new Promise(参数)
中的参数的内容为(resolve, reject) => {代码...}
,这个参数中的代码将会同步的立即执行,异步任务在执行器中执行
then((接受的参数) =>{}, (失败的参数) => {})
,两个函数类型的参数,都会返回一个Promise
对象
catch((失败的参数) => {})
,只能指定失败的回调,执行失败后执行
Promise.resolve(参数)
:
- 如果参数为非
Promise
对象,那么返回的结果为成功的Promise
对象 - 如果参数为
Promise
对象,那么参数的结果决定了返回的结果
如果有一个失败的错误不进行处理,那么此时在控制台可以看到错误信息,程序不会继续执行
Promise.reject(参数)
:
- 直接返回一个失败的参数,程序停止
- 无论传入什么参数,都会返回一个失败的
Promise
Promise.all(数组)
:
-
数组中全部都是
Promise
对象 -
只要有一个失败,就返回一个失败的
Promise
-
只有都成功时才会成功
-
const p1 = new Promise((resolve, reject) => { resolve(); }) const p2 = new Promise((resolve, reject) => { resolve(); }) const p3 = new Promise((resolve, reject) => { resolve(); }) const p4 = new Promise((resolve, reject) => { resolve(); }) const p5 = Promise.resolve("ok"); console.log(Promise.all([p1, p2, p3, p4, p5]));
Promise.race(数组)
:
-
返回新的
Promise
-
数组中第一个返回结果的
Promise
为最终的状态 -
race
中文为赛跑 -
const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve("nb"); }, 1000) }) const p2 = new Promise((resolve, reject) => { setTimeout(() => { resolve("nb"); }, 5000) }) const p3 = new Promise((resolve, reject) => { setTimeout(() => { resolve("nb"); }, 10) }) const p4 = new Promise((resolve, reject) => { setTimeout(() => { resolve("nb"); }, 10000) }) console.log(Promise.race([p1, p2, p3, p4]));
-
p3
率先执行,所以最终的结果为p3
的结果
then((result) => {}, (reason => {}))
的返回值:
-
如果执行成功的回调,那么返回结果由第一个回调的返回值决定
-
let result = p.then((n) => { // 返回成功 console.log("成功的回调" + n); }, (n) => { console.log("失败的回调" + n) });
串联任务
在then
后继续调用then
,例如倒计时3 2 1
:
let count = 3;
new Promise((resolve, reject) => {
setTimeout(() => {
console.log(count);
count--;
resolve();
}, 1000)
}).then(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(count);
count--;
resolve();
}, 1000)
})
}).then(() => {
setTimeout(() => {
console.log(count);
count--;
}, 1000)
})
异常穿透
使用then
进行链式调用时,可以在最后指定异常回调,只需要在最后使用catch
即可,中间的任何一个失败的情况都会被这个catch
处理
let count = 3;
new Promise((resolve, reject) => {
setTimeout(() => {
console.log(count);
count--;
resolve();
}, 1000)
}).then(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(count);
count--;
resolve();
}, 1000)
})
}).then(() => {
setTimeout(() => {
console.log(count);
count--;
}, 1000)
}).catch(e => {
console.log("异常内容:" + e);
})
或者
new Promise((resolve, reject) => {
console.log("1");
resolve();
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
throw "eeee"
}).then(() => {
console.log(4);
}).then(() => {
console.log(5);
}).catch(e => {
console.log("异常为:" + e);
})
中断链
也就是把then
调用链中断,需要返回一个pending
状态的promise
即return new Promise((resolve, reject) => {})
new Promise((resolve, reject) => {
console.log("1");
resolve();
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
// 中断
return new Promise((resolve, reject) => {});
}).then(() => {
console.log(4);
}).then(() => {
console.log(5);
}).catch(e => {
console.log("异常为:" + e);
})
async函数
返回值为Promise
对象,结果由async
函数执行的返回值决定
定义:
let fun = async () => {
}
// 或者
let fun2 = async function() {
}
例如:
const fun = async () => {
return {
username: "用户名",
password: "密码"
};
}
let promise = fun();
console.log(promise)
promise.then(result => {
console.log(result)
})
输出结果:
Promise { { username: '用户名', password: '密码' } }
{ username: '用户名', password: '密码' }
如果返回的是一个Promise
那么:
const fun = async () => {
return new Promise((resolve, reject) => {
resolve({
username: "用户名",
password: "密码"
});
})
}
let promise = fun();
console.log(promise)
promise.then(result => {
console.log(result)
})
在14
行取出的内容不变:
Promise { <pending> }
{ username: '用户名', password: '密码' }
也是可以抛出异常的,catch
中得到的错误内容就是抛出的内容:
const fun = async () => {
throw {
code: 404,
content: "未找到资源"
}
}
let promise = fun();
console.log(promise)
promise.then(result => {
console.log(result)
}).catch(e => {
console.log(`异常,状态码为:${e.code},内容为:${e.content}`);
})
结果:
异常,状态码为:404,内容为:未找到资源
await
右侧如果是promise
对象,返回的值为promise
成功的值
右侧如果是其他类型的值,直接返回相应的值
必须要在async
函数中使用await
,如果执行失败则需要通过try-catch
进行处理
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
code: 8888,
msg: "消息"
})
}, 2000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject({
code: 9999,
msg: "消息2"
})
}, 2000)
})
const getValP = async () => {
let obj = await p;
console.log(obj)
}
const getValP2 = async () => {
try {
let obj = await p2;
console.log(obj)
} catch (e) {
console.log("抛出异常:" + JSON.stringify(e));
}
}
getValP();
getValP2();
结果:
{ code: 8888, msg: '消息' }
抛出异常:{"code":9999,"msg":"消息2"}
Q.E.D.