深入浅出Promise
异步编程(JS基础的三大概念之一)
基础概念:同步行为和异步行为是计算机科学的一个基本概念。 JavaScript是单线程的,在单线程事件循环(event loop)模型中, 同步操作与异步操作是代码核心机制之一。
同步异步代码特点:
- 异步不会阻塞代码的执行
- 同步会阻塞代码的执行
代码演示
// 同步代码
console.log(1)
alert(2)
console.log(3)
// 异步代码
console.log(1)
setTimeout(console.log, 0, 2)
console.log(3)
常见异步的应用场景
- setTimeout、setInterval
- 网络请求(ajax)
Promise 是ES6里面新增异步编程的方案,Promise 生来就是为了解决异步操作的问题。在之前都是使用的回调函数来处理异步的, 比如Jquery中的$.get(),如果一个网络请求依赖前一个网络请求,就会写成如下:
$.get('/any.do', (res)=> {
$.get(`/any1.do${res.id}`, (res2) => {
$.get(`/any2.do`, (res3)=> {
console.log(res3)
})
})
})
很显然,随着代码越来越复杂,回调策略是不具备扩展性的。“回调地狱”这个称呼就是名至实归了,代码维护起来就是噩梦。 使用Promise改写后的样子
function getData(url){
return new Promise((resolve, reject)=> {
$.get(url, (res) => {
resolve(res)
},(err)=> {
reject(err)
})
})
}
getData('/any.do').then((res)=> {
return getData(`/any1.do${res.id}`)
}).then((res)=> {
return getData(`/any2.do`)
}).then((res)=> {
console.log(res)
}).catch(err => {
console.log(err)
})
这样子就是一个串联的程序,只有一层,虽然也是回调的模式,解决了深层次的嵌套的问题。
2010年Commonjs项目的实现的Promise/A规范日益流行起来,这个规范最终成为ES6的实现范本。 PromiseA+规范链接地址: https://promisesaplus.com/ 其他二大核心基础概念(原型原型链、作用域闭包)
Promise基础
- promise状态
promise有三种状态: pending、resolved(fulfilled)、rejected
pending:待定状态,执行了 executor 后,处于该状态
fulfilled:兑现状态,调用resolve()后,Promise 的状态更改为 fulfilled,且无法再次更改
rejected:拒绝状态,调用reject()后,Promise 的状态更改为 rejected,且无法再次更改
// 报错,必须要实现 executor方法
// new Promise()
let p1 = new Promise(()=>{})
let p2 = new Promise((resolve)=>{resolve()})
let p3 = new Promise((resolve,reject)=>{reject()})
let p4 = new Promise((resolve,reject)=>{
resolve()
reject()
})
console.log(p1)
console.log(p2)
console.log(p3)
console.log(p4)
then方法 Promise.prototype.then方法: (onResolved, onRejected) => {}
onResolved函数: 成功的回调函数 (value) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的promise对象
catch方法 Promise.prototype.catch方法: (onRejected) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected)
Promise.resolve方法 Promise.resolve方法: (value) => {} value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象
Promise.reject方法 Promise.reject方法: (reason) => {} reason: 失败的原因
说明: 返回一个失败的promise对象
Promise.all方法 Promise.all方法: (promises) => {} promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
Promise.race方法 Promise.race方法: (promises) => {} promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态
消灭异步回调async/await
- async 标记的函数是一个promise对象
async function fn(){
return true
}
const f = fn()
console.log("::::",f)
f.then((res) => {
console.log(res)
})
- await相当于 Promise then
(async function () {
let p = Promise.resolve(true)
const value = await p // 相当于 Promise then
const value1 = await true // 如果是非promse对象,会包装成promise对象 Promise.resolve(true)
console.log(p)
console.log(value)
console.log(value1)
})()
最后使用async改写后的样子
function getData(url){
return new Promise((resolve, reject)=> {
$.get(url, (res) => {
resolve(res)
},(err)=> {
reject(err)
})
})
}
// 最后catch的地方可以统一在某一处维护处理,代码看起来更加简洁明了
const res = await getData('/any.do')
await getData(`/any1.do${res.id}`)
await getData(`/any2.do`)
再谈Event Loop并且深度探究Promise执行过程
tips: Promise是属于微任务,今天代码就只演示Promise微任务的这种
执行顺序是同步代码(同步代码里面的微任务会推到回调队列里面)-> event loop重新检测回调队列是否有事件 -> 事件队列(清空到推送执行栈)