前端Promise学习记录
自我提问:
- 什么是异步编程,为什么要有这个东西?
- 在 Promise 之前,是靠什么来解决问题的?
Promise 介绍与基本使用
功能说明:Promise 对象用来封装一个异步操作并可以获取其 成功 / 失败 的结果
优势
- 通过链式调用,解决回调地狱问题
- 指定回调函数的方式更加灵活
初体验
写一个抽奖demo
function rand(m,n){
return Math.ceil(Math.random() * (n-m+1) ) + m - 1
}
const btn = document.getElementById('btn')
btn.onclick = () => {
// // 定时器
// setTimeout(() => {
// let n = rand(1,100)
// if (n <= 30) {
// alert('恭喜中奖!')
// } else {
// alert('再接再厉!')
// }
// }, 1000)
// Promise 形式
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1,100)
console.log(n)
if (n <= 30) {
resolve(n)
} else {
reject(n)
}
}, 1000)
})
p.then((value) => {
alert('恭喜中奖!' + value)
}, (reason) => {
alert('再接再厉!' + reason)
})
}
Promise实践练习-fs模块
let p = new Promise((resolve, reject) => {
fs.readFile('./content.tx', (err, data) => {
// 抛出错误
if (err) reject(err)
resolve(data)
})
})
p.then(value => {
console.log(value.toString())
}, reason => {
console.log(reason)
})
进一步封装
/**
* 封装一个 mineReadFile 读取文件内容
* 参数: path 文件路径
* 返回: promise 对象
*/
function mineReadFile(path) {
return new Promise((resolve, reject) => {
require('fs').readFile(path, (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
mineReadFile('./content.txt').then(value => {
console.log(value.toString())
}, reason => {
console.log(reason)
})
Promise实践练习-AJAX请求
/**
* 封装一个函数 sendAJAX 发送 GET 请求
* 参数: URL
* 返回: Promise 对象
*/
function sendAJAX(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.responseType = 'json'
xhr.open('GET', url)
xhr.send()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 ) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject(xhr.status)
}
}
}
})
}
sendAJAX('https://api.apiopen.top/getJoke').then(value => {
console.log(value)
}, reason => {
console.warn(reason)
})
util.promisify 方法
可以自动把一个函数封装成一个Promise对象
const fs =require('fs')
let mineReadFile = require('util').promisify(fs.readFile)
mineReadFile('./content.txt').then(value => {
console.log(value.toString())
}, reason => {
console.log(reason)
})
Promise 的状态
PromiseState
- pending 未决定的
- resolved / fullfilled 成功
- rejected 失败 PromiseResult 异步对象成功/失败的结果 resolve/reject 可以对其赋值
Promise API
Promise(excutor){}
executor 会在Promise 内部立即同步调用,异步操作在执行器中执行(?没理解)
Promise.all 方法 (promises) => {}
接收promise数组,返回一个新的promise,只有当所有promise都成功时才成功,否则失败。
成功时返回的promise的result为一个数组,包含所有成功的值。
失败时返回第一个失败的结果
Promise.race 方法
返回第一个改变状态的promise
Promise 关键问题
如何修改对象的状态
- 调用resolve 函数
- 调用reject 函数
- 抛出错误,
throw 'error'
能否执行多个回调
可以,一个promise可以有多个p.then()
Promise状态先改变还是先指定回调
Promise.then() 的返回结果是由什么决定的
- 抛出错误,则返回的是失败的promise
- return 非 Promise 类型的对象,则返回一个成功的Promise,值为return的结果,如果没有return,则为undefined
- return Promise,则继承状态与值
Promise 如何串联多个操作任务
正是由于前一个问题的机制,Promise.then()返回的是一个Promise,所以能够进行链式调用,避免了回调地狱。
Promise 的异常穿透
概念:一条Promise.then()的链式调用,只需要在最后写一个失败的回调即可,这就是异常穿透
中断 Promise 链
如果只是抛出错误之类的方式,整个Promise链条的各个回调依然会继续执行下去,若要直接强行中断,需要返回一个pending的Promise,如return new Promise(()) => {}
Promise 自定义封装
跟着老师手写了一遍 Promise ,写完后感觉非常好,一是再一次锻炼了自己的 JavaScript 水平,二是能够从原理上理解 Promise 是怎么工作的,在应用的时候也能更有自信去把控它。强烈建议大家去手写一遍,同时也认识到这种学习方式也适用于其他地方。
async 与 await
没学之前以为这个很高端,看不懂,学了后发现无非就是一个 Promise 的语法糖而言...让我们写 Promise 更快一点。
这两个都是JS的关键字,async 用于标识一个函数为异步函数,await 用于直接提取到该异步函数的 response,从这里也能够看出,await 必须写在 async 里面。
总结
学得很开心,收获很多。我们要再接再厉。