异步编程Promise和async语法糖
前言:
在ES6中,新增了Promise这个类 用来处理异步代码
一、同步和异步
同步编程:在主线程上排队执行的任务,只有前一个执行完毕,才能执行后一个任务。 按照顺序执行,同步编程容易造成阻塞。
异步编程:不进入主线程,而进入“任务队列(task queue)”的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,这个任务才会进入主线程(异步执行会放在任务队列中加载,加载完毕进入主线程,加载的过程中不影响后面任务的加载。)
二、异步使用场景和分类
使用场景:
- 定时任务 : setTimeout,setInterval
- 网络请求 : ajax请求,动态img添加
- 事件绑定 :点击等交互事件
异步又分为:
- 微任务: promise.then回调, async
- 宏任务: script ,setTimeOut ,setInterval 的回调函数,I/O ,UI交互事件
在事件中,每进行一次循环操作称为tick。分为宏任务(macrotask) 和微任务(microtask) 并且每次宏任务执行完毕,都要清空所有的微任务。
三、Promise用法
Promise 其实是异步编程的一种解决方案.简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,可以从改对象获取异步操作的消息。
它可以解决回调地狱的问题,也就是异步深层嵌套问题
注意:Promise本身是同步执行,Promise里面的回调函数是异步执行
三种状态
- pending(待定)初始状态,既没有被兑现,也没有被拒绝
- fulfilled(已兑现)意味着操作成功完成
- rejected(已拒绝)意味着操作失败。
特点
- Promise.prototype.then 和 Promise.prototype.catch 方法返回的是 promise, 所以它们可以被链式调用
1.用法:
// promise的两个参数都是回调函数
// 参数(名字随便起,但是这两个最好)
// 当第一个回调参数被调用时(resolve被调用),会调用new出来的这个对象下的then方法,then方法中的参数也是个回调函数。
// 当第二个回调参数被调用时(reject被调用),会调用new出来的这个对象下的catch方法,catch方法中的参数也是个回调函数 。
let flag = 1
let promise = new Promise((resolve,reject)=>{
console.log('asd'); // 同步
flag === 1 ? resolve() : reject()
}).then(res=>{
console.log('成功'); // 异步
}).catch(err=>{
console.log('失败'); // 异步
}).finally(result=>{
console.log('执行完毕'); // 异步
})
2.promise的三个实例方法then,catch,finally
then 里面执行的是成功的回调或者失败的回调,catch 里面执行的是错误的回调。
注意:失败和错误是不同的概念,成功和失败都是非错误的,是程序定义的不同状态,而错误是 js 抛出的异常,比如从 null.namejs 就会抛异常,错误是抛出的异常,当然不仅仅是 js 本身的异常,也可以程序员自定义异常。
而findlly在最后都会执行,无论什么情况
四、静态属性
1.resolve方法
方法返回一个以给定值解析后的Promise 对象
定值有以下几种情况:
- 如果这个值是一个 promise ,那么将返回这个 promise
- 参数不是具有then()方法的对象,或根本就不是对象,Promise.resolve()会返回一个新的 Promise 对象,状态为resolved
- 没有参数时,直接返回一个resolved状态的 Promise 对象
2.reject()方法
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected,且[[PromiseResult]]的值为reason
// 两种写法相同
const p = Promise.reject('错误信息')
// [[PromiseResult]]:'错误信息'
const p = new Promise((resolve, reject) => reject('错误信息'))
3.any()方法
- 所有的Promise对象均失败后才会执行any中的失败回调,否则当任意一个Promise对象成功就会直接进入then回调。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('第一个');
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('第二个');
}, 2000);
})
Promise.any([p1, p2]).then((values) => {
console.log('成功', values)
}).catch(reason => {
console.log('失败', reason)
})
4.all和allSettled方法
- all:所有的Promise对象均成功后才会执行all中的then回调,否则返回的是最先rejected状态的值。
- allSettled:Promise对象均出现结果(无论成功或失败)后才会执行allSettled中的then回调(只会进入then回调)。
let p1 = new Promise((resolve,reject) => {
setTimeout(() => {
resolve('sucess1')
}, 1000);
})
let p2 = new Promise((r, t) => {
setTimeout(() => {
resolve('sucess2')
}, 2000);
})
Promise.all([p1, p2]).then((res) => {
console.log(res); // [1,1,1] 以数组的方式返回所有结果
})
// 当其中一个抛出异常 或者执行reject方法时会在执行处阻断Promise,下面的Promise执行就会被阻断
// 如果不中断,可以直接使用allSettled
Promise.allSettled([p1, p2, p3]).then((res) => {
console.log(res); // 以数组的方式返回所有结果
})
五、async
1、asnyc 函数特点:
- 是一个语法糖
- 函数执行时候返回值是一个新的prmise实例对象,(与定义async函数中return 没有关系)
- 返回的promise实例对象的 状态为 fulfilled
语法糖:具有一定功能性的内容,就是语法糖
async function fun() {
// return 给 async fun 返会的promise.[[promiseResult]] 赋值的。
return 'return赋值'
}
let res = fun();
console.log(res);
res返回值
2、awiat的用法
- await 只能在async函数中编写
- await 必须根promise实例对象
- awiat 获取await后的promise实例对象的 [[promiseResult]] 的赋值
因为浏览器编译 不支持 [[xxxx]] 和obj.xxx取值方式,所以要么api 获取 ,要么关键字获取。 所以 [[PromiseResult]] 的获取值有两种方式:await 和 then回调函数形参
async function foo(){
// 语法: await promise实例对象;\
// 作用: 获取await的promise实例对象中的[[PromiseResutl]] 的赋值;
let res = await new Promise((resolve)=>{
console.log('同步代码');
resolve(123) // 给 [[PromiseResutl]] 赋值
})
// ---> = await prmise实例对象(new)
// ----> = resove(实参)
// -----> = [[promiResult]]的赋值
// -----> = 123
console.log(res); // 返回值123
}
foo()
3、[[PromiseResult]]特点:
- 每个promise 实例对象都有该属性
- 赋值方式有以下:
1. new Promise 的resolve() 是实参
2. then 的retrun
3. async 函数的return
3:渎值的方式如下:
1:await
2: then 的回参