文章目录
一、Promise
1、认识Promise
ES6新增的内置类(构造函数),用来规划异步编程代码,用来解决回调地狱问题
Promise的实例肯能由三种状态:
- 原始状态 是pending
- 成功态resolved/fulfilled
- 失败态rejected
实例的状态 :只能由pending变成fulfilled或者rejected;不能由fulfilled变成rejected或者fulfilled(大白话就是 状态只能由pending变成其他,而且只能变一次)
Promise原型上的方法:
then(成功态回调,失败态回调) 返回值是一个新的Promise实例
catch(失败态回调) 兜底上边实例的失败态的
finally(最后的回调)
Promise的静态方法:
- resolve() 创造一个成功态的实例
- reject() 创造一个失败态的实例
- all([p1,p2,p3,p4]) 所有的实例都成功之后 才会执行后边的成功态回调函数
- race([p1,p2,p3,p4]) 只要有一个实例完成状态变换,后边的then就是给这个实例准备的
then
then的第一个回调函数的执行时机: 实例的状态由pending变成fulfilled的时候
then的第一个回调函数的执行接收的实参:resolve执行的时候传递的第一个参数
then的第二个回调函数的执行时机: 实例的状态由pending变成rejected的时候
then的第二个回调函数的执行接收的实参: reject执行的时候传递的第一个参数
第二个回调函数可以把reject的错误信息融掉,不显示在控制台
第二个回调函数可以不写
catch
catch对应的回调函数 什么时候执行 上边的实例出现失败态的时候
catch 兜底的错误是没有被上边兜住的错误
let p1 = new Promise((res, rej) => {
rej(777)
})
p1.then(data => {
console.log('data', data)
}).then(data2 => {
console.log('data2', data2)
console.log(qqq)
}, err2 => {
console.log('err2', err2)
}).catch(err3 => {
console.log('err3', err3)
})
async await
async await 的语法 是为了让编写异步代码 更像是在编写同步代码
async await 需要结合Promise语法才能起作用
async/await:是Promise+Generator的“语法糖”
async是对函数的修饰 -> async function xxx(){…}
- 让函数的返回值自动变味promise实例
- 函数执行报错,则返回状态是rejected,值是报错原因的实例
- 如果执行不报错,在看返回值
- 返回值是新的实例,则以自己返回的promise实例为主
- 其它情况都返回一个状态是fulfilled,值是返回值的实例
- 可以在函数中使用await
await可以监听promise实例的状态,从而决定去做啥事 -> let xxx = await [promise实例]; - 必须出现在一个函数中,并且是经过async修饰的函数
- await后面需要跟一个promise实例「如果不是promise实例,浏览器也会把其变为promise实例」
await 14; => await Promise。resolve(14); - await会“等待”后面实例的状态为“成功”时,再把“当前上下文”中,await“下面”的代码执行!xxx就是当前实例状态为成功返回的结果
- 如果await后面的实例状态是失败,则下面代码不会执行(控制台报红,但是不影响其它代码执行)!!
- 我们是基于try/catch实现对await后面的实例为失败态的处理,避免报红
练习题
1、
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
答案:
'script start'
'async1 start'
'async2'
'promise1'
'script end'
'async1 end'
'promise2'
'setTimeout'
2、
let body = document.body;
body.addEventListener('click', function () {
Promise.resolve().then(() => {
console.log(1);
});
console.log(2);
});
body.addEventListener('click', function () {
Promise.resolve().then(() => {
console.log(3);
});
console.log(4);
});
答案:2 1 4 3
finally
对应的回调会在最后不管前边是成功了还是失败了 ,都会走 finally对应的回调函数没有参数
Promise.resolve(10)
.then(value => {
console.log('成功', value);
return value * 10;
})
.then(value => {
console.log('成功', value);
return Promise.reject(value * 10);
})
.then(value => {
console.log('成功', value);
return value * 10;
})
.catch(reason => {
console.log('失败', reason);
})
.finally(()=>{
//不论成功还是失败,最后都有要执行finally中的方法「一般不用」
});
2、Promise:
ES6新增的内置类(构造函数),用来规划异步编程代码,用来解决回调地狱问题
let p1=new Promise([executor])
-
[executor]必须是一个函数,而且new Promise的时候会立即把其执行 “同步”
-
p1是其创建出来的实例
私有属性
- [[PromiseState]]:“pending”、“fulfilled”、“rejected”实例的状态
- [[PromiseResult]]:undefined 实例的值「成功的结果或者失败的原因」
共有属性
- then
- catch
- finally
- …
-
p1.then([onfulfilled],[onrejected])
- [onfulfilled]/[onrejected]都是函数
- 实例的状态是成功fulfilled的时候,会把[onfulfilled]执行,并且把实例的值作为成功的结果传递给他
- 实例状态是失败rejected的时候,会把[onrejected]执行,把实例值作为失败的原因传递给他
3、如何修改实例的状态和值
@1 基于这种方式创建实例 let p=new Promise(()=>{ 。。。})
- resolve/reject也是函数
- resolve(‘ok’) -> 把实例p的状态修改为fulfilled,值(成功结果)是‘OK’
- rejected(‘no’) -> 把实例p的状态修改为rejected,值(失败原因)是‘NO’
- 如果executor函数执行报错,则把实例的状态修改为rejected,值是报错原因「不会抛错」
- 一但状态被修改fulfilled或者rejected,后期就不会在更改状态值了
@2 每一次执行then方法,都会返回一个“全新的promise实例”
let p2=p1.then(onfulfilled,onrejected);
不论onfulfilled执行还是onrejected执行(由p1状态来决定),方法的执行决定了p2的状态和值
- 首先看方法执行是否报错,如果报错了,则p2是失败态(rejected),值是报错原因
- 如果执行不报错,在看方法的返回值
- 如果返回的是“promise实例 -> @NP”,则@NP的状态和值直接决定了p2的状态和值
- 如果返回的不是新实例,则p2状态是成功(fulfilled),值是函数的返回值
@3 执行Promise.resolve/reject/all/any/race…等静态私有方法,也会创建新的Promise实例
- Promise.resolve(10) 创建一个状态是成功fulfilled,值是10的实例
- Promise.reject(10) 创建一个状态是失败的rejected,值是0的实例
二、THEN链的穿透/顺延机制
- .then(onfulfilled,onrejected),两个方法可以传可以不传,如果不传,则顺延至下一个then中,相同状态要执行的方法中去处理!!
- 原理:我们不设置对应的方法,Promise内部会默认加一个对应的方法,可以让其实现状态的顺延/穿透
p.catch(onrejected) 等价于 p.then(null,onrejected)
三、关于Promise.all/any/race 三个方法的研究
let p=Promise.all([Promises]);
- promises是包含零到多个promise实例的集合,一般是数组!如果集合中的某一项不是promise实例,则默认变为状态为成功,只是本身的promise实例!!
- all:集合中的每个实例都为成功,最后结果p才是成功,值是按照集合顺序,依次存储每个实例成功的结果的数组;
其中只要一个实例失败,则p就是失败,值是本次失败的原因,后面的操作不在处理!! - any:只要有一个成功,最后p就是成功,值是本次成功的结果;都失败,最后p才是失败!!「兼容性不好」
- race:集合中谁最先知道结果,则以谁的为主!
四、AJAX的串行和并行
1、并行
并行:多个请求同时发送即可,谁先回来先处理谁,主要用于多个请求间没有依赖「偶尔我们需要监测,多个请求都成功,整体再去做啥事 => Promise.all」
2、串行
串行:多个请求之间存在依赖,上一个请求成功,我们才能发送下一个(往往是下一个请求需要用到上一个请求的结果,才需要这样处理)
注意:在项目中发送ajax请求都是“采用异步编程”