Promise
1.什么是异步编译
js是单线程,需要借助系统其他线程,js给系统派发任务,系统完成之后交给js异步编程;先把主任务完成之后,再通过轮询的方式遍历任务队列(不断轮询遍历任务队列)
2.Js异步编译
同步是按照编写的代码顺序执行,异步不按照代码顺序执行
主线程作为一个线程,不能接受多方面请求,如果,当一个事件还没有结束,此时界面无法处理其他请求。为了避免这种情况,通常使用子线程来完成一些耗时长的任务。子线程是独立与主线程的,所以子线程出现堵塞情况也不会影响到主线程的运行。
但是子线程有一个局限:一旦发射就会与主线程失去同步,这也就导致了我们无法确定子线程中的任务什么时候结束,因为当结束之后还需要处理其他任务。为了解决这一问题,js中的异步操作函数往往通过回调函数来进行异步任务的结果处理。
回调函数:函数不是程序员进行调用的,而是由程序调用
异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行相应的回调函数。例如ajax的success,complete,error也都指定了各自的回调函数,这些函数就会加入任务队列中,等待执行。
3.任务排序
任务,先进任务队列则先被执行到。
当有两个文件a和b,并且a文件是依赖与b的,但是如果a文件没有被执行就执行了b,则会报错,因为b里面包含a,但是此时a没有被加载到,所以会找不到会产生错误。此时就需要进行嵌套,将a文件的调用嵌套在b里面。
4.Promise什么时候会使用
promise常用于在获取异步请求,比如我们用的axios就是一个promise
5.Promise是为了解决什么问题
promise就是为了解决层次复杂的回调地狱问题的产生
6.Promise微任务处理机制
then为任务,可以添加多个微任务
// 创建一个Promise构造函数,
// 大括号包含起来的部分是pending准备阶段
// 准备阶段有两种结果:成功resolve(),拒绝reject()
new Promise((resolve,reject)=>{
// reject('拒绝状态');
resolve('成功状态');
}).then((value)=>{
// then方法是对结果进行回调函数处理
console.log('成功执行的业务处理')
},reason=>console('拒绝业务处理'))
// 后面的reason是对拒绝状态的业务处理
7.同步任务、宏任务、微任务的执行顺序
同步执行的优先级最高>微任务>宏任务
new Promise返回的是一个Promise,Promise.then返回的也是一个Promise
new Promise(resolve => {
resolve()
console.log('同步任务1')
}).then(value => console.log('成功'))
console.log('同步任务2')
其中new Promise({})这部分是同步任务,和console.log('同步任务2')是顺序执行的
.then()当程序执行到这会把它加载到微任务队列中
显示结果为:同步任务1 同步任务2 成功
8.Promise单一状态与状态中断,基本用法
promise的状态改变之后是不可逆的(此时任务就产生了)不能再进行撤销了
promise只能发送成功或者拒绝其中一个状态
在.then方法中对结果进行回调函数处理时候,如果直接收对拒绝状态的处理(null,reject=>)这个null不能省略,相当于一个占位
9.then返回值的处理技巧
下面的then能接收到上边then的返回值,默认情况下then返回的promise就是成功状态,所以最后一个then进行成功状态的回调函数处(链式)
简单来说:一个Promise对应一个解决方法.then,then需要等待Promise有了状态才会进行处理。
let p1 = new Promise((resolve, reject) => {
resolve('fulfilled');
}).then(value => {
console.log(value)
return "返回Promise"
},
reason => consloe.log('error' + reason)
)
.then(value => console.log(value))
输出结果为:fulfilled 返回Promise
10.其他类型的Promise封装
可以将类、对象、方法等都封装为promise,只要有then就会返回一个promise对象,可以直接将其作为promise来进行使用。
下面举例说明一下:
let p1 = new Promise((resolve, reject) => {
resolve("fulfilled")
}).then(
value => {
// return new Promise((resolve, reject) => {
// // 返回一个Promise
// resolve("成功")
// })
// return {
// // 返回的是一个对象的时候接收的值也是一个普通的对象
// name:"xinyi"
// }
// return {
// // 返回的这个then也是封装成了一个Promise对象
// then(resolve, reject) {
// setTimeout(()=>{
// resolve('这是对象')
// },2000)
// }
// }
// class Hd {
// then(resolve, reject) {
// setTimeout(() => {
// resolve('这是对象')
// }, 2000)
// }
// }
// return new Hd()
return class {
static then(resolve, reject) {
resolve("这是一个静态方法")
}
}
}
)
.then(
value => console.log(value)
)
11.将Promise封装到函数里
将Promise封装到函数里面,如果状态没有改变,then也不会执行
function request() {
return new Promsie((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
})
}
// 将Promise封装到函数里面,如果状态没有改变,then也不会执行
request().then(value => console.log(value))
12.Promise多种错误监测与catch使用
let p1 = new Promise((resolve, reject) => {
// reject(new Error('错误的第一种写法'))
// throw new Error('错误的第二种写法')
// hd+1 没有定义就是用变量产生的错误
// resolve("成功")
reject('拒绝')
}).then(value => {
return new Promise((resolve, reject) => {
reject('p2')
})
})
.then(value => console.log("当只对成功进行处理"))
// 当上一个then接收到的promise是一个错误的状态,但是在then里面没有进行相应的错误处理,就会到catch里面进行错误处理
.catch(error => console.log("对异常的统一处理" + error))
// 推荐做法就是把catch放到最后来捕获错误
13.使用finally实现异步加载动画
注:元素id会在window下自动生成变量,在js中可以直接通过id进行访问。.finally(()=>{})不论是成功或者失败状态,都会执行到。
<div>loading</div>
<script>
const promise = new Promise((resolve, reject) => {
resolve('123hhh')
}).then(msg => {
console.log('resolve')
})
.finally(() => {
console.log('永远会执行(加载),不管成功或者失败')
})
</script>
14.Promise异步加载图片
function loadImg(src) {
return new Promise((resolve, reject) => {
// 实例化出一个图片对象
const image = new Image()
// 指定图片的来源就是src
image.src = src
// 当图片加载成功的时候来改变Promise的状态
image.onload = () => {
resolve(image)
}
// 如果图片加载失败的时候改变它的状态为拒绝状态
image.onerror = reject
document.body.appendChild(image)
})
}
// 这个图片加载好之后可以对他进行处理
loadImg('image/zhengjian.jpg').then(image =>
image.style.border = "solid 2px #ddd"
)
15.封装setTimeout定时器
// setTimeout(()=>{
// console.log('123')
// },2000)
// 用Promise封装一个定时器
function timeout(delay = 1000) {
return new Promise(resolve => setTimeout(resolve, delay))
}
// 调用这个定时器,并进行操作
timeout(2000).then(() => {
console.log("123")
return timeout(2000)
}).then(value => {
console.log("456")
})
16.构建扁平化的setInterval
<div></div>
<script>
function interval(dalay = 1000, callback) {
return new Promise(resolve => {
let id = setInterval(() => {
callback(id, resolve)
}, dalay)
})
}
interval(100, (id, resolve) => {
// clearInterval(id)
// resolve()
const div = document.querySelector("div")
let left = parseInt(window.getComputedStyle(div).left)
div.style.left = left + 10 + 'px'
if (left >= 200) {
clearInterval(id)
resolve(div)
}
}).then(div => {
return interval(100, (id, resolve) => {
let width = parseInt(window.getComputedStyle(div).width)
div.style.width = width - 10 + "px"
if (width <= 30) {
clearInterval(id)
resolve(div)
}
})
}).then(div => {
div.style.backgroundColor = "green"
})
</script>
17.script脚本的Promise加载引擎
function loadScript(src) {
return new Promise((resolve, reject) => {
// 创建了一个script标签(定义一个脚本节点)
const script = document.createElement("script")
// 将src指向传递过来的src
script.src = src
// 加载之后成功执行的回调函数
script.onload = () => resolve(script)
script.onerror = reject
document.body.appendChild(script)
})
}
loadScript('js/hd.js')
.then(script => {
return loadScript('js/houdunren.js')
}).then(script => {
houdunren()
})
function hd() {
console.log("hd.js")
}
function houdunren() {
hd()
console.log('houdunren.js')
}