个人博客:Promise学习笔记(一)
一直有在用Promise,但是没有系统学过Promise,自然也不知道原理。现在就来学习一波。
Promise是JS中进行异步编程的新解决方案。在这之前使用过回调函数进行异步编程。
Promise是一个构造函数,Promise对象用来封装一个异步操作并可以获取其成功或失败的结果值
回调地狱:回调函数嵌套使用
回调地狱导致的问题:
阅读困难(后期维护麻烦)
不便于异常处理
先来一个抽奖示例(隔1s后出结果)
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Promise初体验title>
head>
<body>
<button class="btn" id="btn">抽奖button>
<script>
function rand() {
return Math.floor(Math.random() * 100 + 1) // 返回1到100之前的随机数
}
const btn = document.querySelector("#btn")
btn.addEventListener("click", function () {
setTimeout(() => {
let n = rand()
if (n <= 50) {
alert("恭喜你中奖了")
} else {
alert("很遗憾,你没有中奖")
}
}, 1000)
})
script>
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Promise初体验title>
head>
<body>
<button class="btn" id="btn">抽奖button>
<script>
function rand() {
return Math.floor(Math.random() * 100 + 1) // 返回1到100之前的随机数
}
const btn = document.querySelector("#btn")
btn.addEventListener("click", function () {
const p = new Promise((resolve, reject) => {
// resolve 成功后执行的函数
// reject 失败后执行的函数
let n = rand()
setTimeout(() => {
if (n <= 50) {
resolve(n) // 可以将Promise的状态设置为成功
} else {
reject(n) // 可以将Promise的状态设置为失败
}
}, 1000)
})
p.then(
// 通过then方法指定成功或失败时的回调函数,第一个参数是成功时的回调,第二个参数是失败时的回调
(value) => {
alert(`恭喜你,中奖了,中奖号码是${value}`)
},
(value) => {
alert(`真遗憾,你没有中奖,中奖号码是${value}`)
}
)
})
script>
body>
html>
const fs = require('fs')
fs.readFile('./resource/content.txt', (err, data) => {
if (err) {
throw err
}
console.log(data.toString())
})
const fs = require('fs')
let p = new Promise((resolve, reject) => {
fs.readFile('./resource/content1.txt', (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
p.then((value) => {
console.log(value.toString())
}, (reason) => {
console.log(reason)
})
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise封装AJAXtitle>
head>
<body>
<script>
(function () {
// 1. 创建对象
const xhr = new XMLHttpRequest()
// 2. 初始化
xhr.open('GET', 'https://qcgx2i.api.cloudendpoint.cn/hello') // 接口可能会无效,换一个有效的就行
// 3. 发送
xhr.send()
// 4. 处理响应结果
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response)
} else {
console.log(xhr.status)
}
}
}
})()
script>
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise封装AJAXtitle>
head>
<body>
<script>
(function () {
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://qcgx2i.api.cloudendpoint.cn/hello');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response) // 成功
} else {
reject(xhr.status)
}
}
};
})
p.then((data) => {
console.log(data)
}, (statusCode) => {
console.warn(statusCode)
})
})()
script>
body>
html>
util.promisify():传入一个遵循常见的错误优先的回调风格的函数(即以(err, value) => {...}
作为最后一个参数),并返回Promise版本。
const fs = require('fs')
const { promisify } = require('util')
let pReadfile = promisify(fs.readFile) // 把callback形式的异步api转化成promise形式的
pReadfile('./resource/content.txt')
.then(value => {
console.log(value.toString())
})
实例对象中的一个属性[[PromiseState]]
,有三个值
Promise的状态改变只有两种可能,且只能改变一次:
成功的结果数据一般称为value
,失败的结果一般称为reason
实例对象中的一个属性[[PromiseResult]]
,保存着异步任务成功或失败的结果
只能通过resolve()
或reject()
对PromiseResult
进行修改
const fs = require('fs')
let p = new Promise((resolve, reject) => {
fs.readFile('./resource/content1.txt', (err, data) => {
if (err) {
reject(err) // 通过reject()设置PromiseResult的值
} else {
resolve(data)
}
})
})
p.then((value) => { // 把PromiseResult的值取出来,进行相关操作
console.log(value.toString())
}, (reason) => {
console.log(reason)
})
excutor函数:执行器, (resolve, reject) => {}
resolve函数:内部定义成功后调用的函数
reject函数:内部定义失败后调用的函数
构造函数会在Promise立即同步调用,异步操作在执行器中执行
let p = new Promise((resolve, reject) => {
console.log(1)
})
console.log(2)
// 先输出1,再输出2
语法:promise.then(onResolved, onRejected)
onResolved函数:成功的回调函数, value => {}
onRejected函数:失败的回调函数, reason => {}
返回新的Promise对象
与上面的then()类似,不过只能指定失败的回调函数
作用:接受一个参数,返回一个成功或失败的Promise对象。能够快速封装一个值,将这个值转化为Promise对象
如果传入的参数是非Promise类型的对象,如字符串、数字等,则返回的结果是成功的Promise对象
如果传入的参数是Promise对象,则参数的结果决定resolve的结果,即参数是成功的Promise对象的话,resolve的结果是成功的,反之是失败的
const p1 = Promise.resolve(123) // Promise { 123 }
console.log(p1)
const p2 = Promise.resolve(p1) // 参数为成功的Promise对象
console.log(p2)
const p3 = Promise.resolve(new Promise((resolve, reject) => { // 参数为失败的Promise对象
reject('Error')
}))
p3.catch(reason => {
console.log(reason)
})
接受一个参数,返回一个失败的Promise对象
const p1 = Promise.reject(123)
console.log(p1)
const p2 = Promise.reject(new Promise((resolve, reject) => {
resolve('传参为成功的Promise对象')
}))
console.log(p2)
参数:promises,promise的数组
返回一个新的Promise,当所有的promise都成功才成功,且结果为成功的结果组成的数组;有一个失败就直接失败,返回的结果就是失败的那一个的结果
const p1 = new Promise((resolve, reject) => {
resolve('p1: OK')
})
const p2 = Promise.resolve('p2: OK')
const result1 = Promise.all([p1, p2]) // 所有Promise的结果都成功
console.log(result1)
const p3 = Promise.resolve('p3: OK')
const p4 = Promise.reject('p4: Err')
const p5 = Promise.reject('p5: Err')
const result2 = Promise.all([p3, p4, p5]) // 有Promise的结果失败
console.log(result2)
如果想要捕捉异常,直接链式调用即可
const p3 = Promise.resolve('p3: OK')
const p4 = Promise.reject('p4: Err')
const p5 = Promise.reject('p5: Err')
const result2 = Promise.all([p3, p4, p5])
console.log(result2)
result2.catch(reason => {
console.log(reason)
})
参数:promises,promise的数组
返回一个新的Promise,第一个完成的结果是成功则成功,反之则失败
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1: OK')
})
})
const p2 = Promise.reject('p2: Err')
const result1 = Promise.race([p1, p2])
console.log(result1) // [[PromiseResult]]: "p2: Err"
result1.catch(reason => {
console.log(reason)
})
学习视频:尚硅谷Web前端Promise教程从入门到精通