Promise学习笔记
Posted 做个机灵鬼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Promise学习笔记相关的知识,希望对你有一定的参考价值。
Promise是什么?
1.抽象表达:
Promise是JS中进行异步编程的新方案(旧的是谁?)
2.具体表达:
(1)从语法上来说: Promise是一个构造函数
(2)从功能上来说: Promise对象用来封装一个异步操作并可以获取其结果
promise实例对象的状态改变
1.pending变为fulfilled
2.pending变为rejected
说明: 只有这2种, 且一个promise对象只能改变一次,无论变为成功还是失败, 都会有一个结果数据, 成功的结果数据一般称为vlaue, 失败的结果数据一般称为reason
为什么要用Promise
支持链式调用, 可以解决回调地狱问题
1.什么是回调地狱?
回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件
2.回调地狱的缺点?
不便于阅读
不便于异常处理
3.一个不是很优秀的解决方案?
promise链式调用
4.终极解决方案?
async/await
API
1.Promise构造函数: Promise (excutor)
(1)excutor函数: 执行器 (resolve, reject) =>
(2)resolve函数: 内部定义成功时我们调用的函数 value =>
(3)reject函数: 内部定义失败时我们调用的函数 reason =>
说明: excutor会在Promise内部立即同步回调
,异步操作其中执行
2.Promise.prototype.then方法: (onFulfilled, onRejected) =>
(1)onFulfilled函数: 成功的回调函数 (value) =>
(2)onRejected函数: 失败的回调函数 (reason) =>
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
返回一个新的promise对象
3.Promise.prototype.catch方法: (onRejected) =>
(1)onRejected函数: 失败的回调函数 (reason) =>
说明: then()的语法糖, 相当于: then(undefined, onRejected)
4.Promise.resolve方法: (value) =>
(1)value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象
5.Promise.reject方法: (reason) =>
(1)reason: 失败的原因
说明: 返回一个失败的promise对象
6.Promise.all方法: (promises) =>
(1)promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7.Promise.race方法: (promises) =>
(1)promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态
改变promise状态和指定回调函数谁先谁后?
(1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2)如何先改状态再指定回调?
①在执行器中直接调用resolve()/reject()
②延迟更长时间才调用then()
(3)什么时候才能得到数据?
①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
promise.then()返回的新promise的结果状态由什么决定?
(1)简单表达: 由then()指定的回调函数执行的结果决定
①如果抛出异常, 新promise变为rejected, reason为抛出的异常
②如果返回的是非promise的任意值, 新promise变为fulfilled, value为返回的值
③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
<script type="text/javascript" >
// Promise的的then()方法返回的是一个【新的的Promise实例对象】
/*
这个新的promise实例对象 它的值和状态由什么决定
简单的说:由then所指定的回调函数的执行结果决定
详细的说:
1.如果then所指定的回调函数执行的结果为非Promise值 a
那么【新的的Promise实例对象】的状态为 :成功fulfilled,成功的值为a
2.如果then所指定的回调函数执行的结果是实例Promise对象p
那么【新的的Promise实例对象】的状态和值都与p一致
3.如果then所指定的回调抛出异常
那么【新的的Promise实例对象】状态为reject err的原因为抛出的那个异常
*/
const p = new Promise((resolve,reject)=>
setTimeout(()=>
resolve(100)
,1000)
)
p.then(
//value这个回调 如果没有指定返回值 全局会帮自动返回一个undefind
value => console.log('成功了1',value); return 900,
reason => console.log('失败了1',reason);
).then(
value => console.log('成功了2',value); return Promise.resolve(800),
reason => console.log('失败了2',reason);
).then(
// 如果返回一个失败的promise实例 那么将会走失败的回调
value => console.log('成功了3',value); return Promise.reject(700),
reason => console.log('失败了3',reason);
).then(
value => console.log('成功了4',value);,
reason => console.log('失败了4'); return 600
).then(
value => console.log('成功了5',value); throw 500,
reason => console.log('失败了5');
).then(
value => ,
reason => console.log('失败了6',reason);
)
</script>
promise异常传透?
(1)当使用promise的then链式调用时, 可以在最后指定失败的回调,
(2)前面任何操作出了异常, 都会传到最后失败的回调中处理
<script type="text/javascript">
// promise错误穿透
/*
promise的then()方法链式调用的时候,不用每个then方法里面都写失败的回调
只需要写在最后一个catch()函数
*/
function sendAjax(url, data)
return new Promise((resolve, reject) =>
const xhr = new XMLHttpRequest();
//绑定监听
xhr.onreadystatechange = () =>
if (xhr.readyState === 4)
if (xhr.status >= 200 && xhr.status < 300)
resolve(xhr.response);
else reject("失败了");
;
let str = "";
for (key in data)
str += `$key=$data[key]&`;
str.slice(0, -1);
xhr.open("GET", url + "?" + str);
xhr.responseType = "json";
xhr.send();
);
sendAjax("https://api.apiopen.top/getJoke", name: "小刘", age: "18" )
.then(
(value) =>
console.log("成功了1", value);
return sendAjax("https://api.apiopen.top/getJoke2",
name: "小刘",
age: "18",
);
,
// reason => console.log('失败了1'); return new Promise(()=>)
//错误穿透底层原理 每一个then方法自动帮补了一个抛出异常
//那么then返回的为一个失败promise的对象
(reason) =>
throw Error;
)
.then(
(value) =>
console.log("成功了2", value);
return sendAjax("https://api.apiopen.top/getJoke", name: "小刘",age: "18",
);
// reason => console.log('失败了2');
)
.then(
(value) => console.log("成功了3", value);
// reason => console.log('失败了3');
)
.catch((reason) =>
console.log("出错了");
);
</script>
async 函数
1.函数的返回值为promise对象
2.promise对象的结果由async函数执行的返回值决定
await 表达式
1.await右侧的表达式一般为promise对象, 但也可以是其它的值
2.如果表达式是promise对象, await返回的是promise成功的值
3.如果表达式是其它值, 直接将此值作为await的返回值
注意
1.await必须写在async函数中, 但async函数中可以没有await
2.如果await的promise失败了, 就会抛出异常, 需要通过try…catch捕获处理
<script type="text/javascript" >
//async和await的使用
const p1 = new Promise((resolve,reject)=>
setTimeout(()=>
resolve('a');
,1000)
);
const p2 = new Promise((resolve,reject)=>
setTimeout(()=>
reject('一些错误');
,2000)
);
const p3 = new Promise((resolve,reject)=>
setTimeout(()=>
resolve('c');
,3000)
);
;( async()=>
try
//await可以等待成功的promise实例对象的返回值
const result1 = await p1;
console.log(result1);
const result2 = await p2;
console.log(result2);
const result3 = await p3;
console.log(result3);
catch (error)
console.log(error);
)()
</script>
宏队列和微队列
1.JS中用来存储待执行回调函数的队列包含2个不同特定的列队
2.宏列队: 用来保存待执行的宏任务(回调), 比如: 定时器回调/DOM事件回调/ajax回调
3.微列队: 用来保存待执行的微任务(回调), 比如: promise的回调/MutationObserver的回调
.JS执行时会区别这2个队列
(1)JS引擎首先必须先执行所有的初始化同步任务代码
(2)每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行
(3)微队列的优先级比宏队列高
下面来看一道面试题
<script type="text/javascript" >
// 宏队列和微队列
setTimeout(()=>
console.log('setTimeout1');
//在执行这个回调时,输出setTimeout1 再把then方法的回调放入伪队列
//在执行setTimeout2前 先把这个微任务执行了 因为优先级的
Promise.resolve(2).then(
value => console.log('成功了Promise2');
)
)
setTimeout(()=>
console.log('setTimeout2');
)
Promise.resolve(3).then(
value => console.log('成功了Promise3');
)
Promise.resolve(4).then(
value => console.log('成功了Promise3');
)
</script>
以上是关于Promise学习笔记的主要内容,如果未能解决你的问题,请参考以下文章