一、.Promise对象详解
1. Promise是什么
- 是JS中进行异步编程的新解决方案(旧方案是用回调函数)
- 语法:Promise是一个构造函数
- 功能:Promise对象用来封装一个异步操作并获取其成功或者失败的结果值
2. Promise的优点
- 支持链式调用,可以解决回调地狱问题
- 回调地狱:回调函数的嵌套调用
- 回调地狱的缺点:不便于阅读,不便于异常处理(无法精确定位是哪一个回调函数出了问题)
3. 异步编程
- fs文件操作
- 数据库
- AJAX
- 定时器
4. then(onFulfilled, onRejected):
用于指定Promise对象成功或者失败的回调函数
-
onFullfilled:成功回调函数
-
onRejected:失败回调函数
-
实例一:读取文件
const fs = require('fs') //原始方法 // fs.readFile('./resource/content.txt', (err, data) => { // if (err) throw err; // console.log(data.toString()); // }) // Promise形式 const p = new Promise((resolve, reject) => { fs.readFile('./resource/content1.txt', (err, data) => { if (err) reject(err); resolve(data) }) }) //调用then指定失败和成功执行的函数 p.then((value) => { console.log(value.toString()) }, (reason) => { console.log(reason); })
-
实例二:AJAX请求
const p = new Promise((resolve, reject) => { //1.创建对象 const xhr = new XMLHttpRequest(); //2.初始化 xhr.open('GET', "https://api.apiopen.top/getJoke") //3.发送 xhr.send() //4.处理响应结果 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { // console.log(xhr.response); resolve(xhr.response) } else { // console.log(xhr.status); reject(xhr.status) } } } }) p.then((value) => { console.log(value); }, (reason) => { console.warn(reason); })
-
实例三:封装文件请求函数返回值为一个promise对象
function mineReadFile(path) { return new Promise((resolve, reject) => { require('fs').readFile(path, (err, data) => { if (err) reject(err) resolve(data) }) }) } mineReadFile('./resource/content.tx').then( (value) => { console.log(value.toString()); }, (reason) => { console.log(reason); })
5. util.promisify 方法:
传入一个错误优先的函数((err,value)=>....
),返回一个promise
const util = require('util')
const fs = require('fs')
const { log } = require('console')
//返回一个新函数
let mineReadFile = util.promisify(fs.readFile)
mineReadFile('./resource/content.txt').then(value => {
console.log(value.toString())
}
)
6. promise的状态改变
-
状态:实例对象中的属性【PromiseState】
-
三种值:pending, resolved, rejected
-
pending=>resolved
-
pending=>rejected
-
只能改变一次,通过
resolve
、reject
和抛出异常方法改变
7.Promise 对象的值
- 实例对象中的一个属性【PromiseResult】,保存对象【成功、失败】的结果
- 只有 resolve 和 reject 函数可以改变这个值
8. Promise的基本执行流程
9. Promise的API
-
Promise的构造函数:
Promise(executor){}
- executor 函数:执行器
(resolve, reject)=>{}
,同步调用,异步操作在执行器内执行 - resolve 函数:内部定义成功时调用的函数
value=>{}
- reject 函数:内部定义失败时调用的函数
reason=>{}
- executor 函数:执行器
-
Promise.prototype.then(onResolved, onRejected)
- onResolved 函数:成功的回调函数
value=>{}
- onRejected 函数:失败的回调函数
reason=>{}
- 说明:返回一个新的Promise对象
- onResolved 函数:成功的回调函数
-
Promise.prototype.catch(onRejected)
-
Promise.resolve()
//如果传入的参数为非Promise对象,则返回为成功的Promise对象 let p1 = Promise.resolve(521); //如果传入参数为Promise对象,则参数结果决定了resolve的结果 let p2 = Promise.resolve(new Promise((resolve, reject) => { reject('Error') })) p2.catch(reason => { console.log(reason); }) console.log(p2);
5.Promise.reject()
:返回一个失败对象
6.Promise.all(promise数组)
返回一个新的 Promise对象,只有所有promise都成功,才成功,只要有一个失败了就直接失败
let p1 = new Promise((resolve, reject) => {
resolve('ok')
})
let p2 = Promise.resolve('Success')
let p3 = Promise.resolve('Oh Yeah')
const result = Promise.all([p1, p2, p3])
console.log(result);
7. Promise.race(promise数组)
:返回一个新的Promise,第一个完成的promise的结果状态就是最终状态
10. Promise中的关键问题
-
如何改变promise的状态
-
resolve(value):如果当前是pending就会变成resovled
-
reject(reason):如果当前是pending就会变成rejected
-
抛出异常:如果当前是pending就会变成rejected
const p = new Promise((resolve, reject) => { throw 'ERROR' }) console.log(p);
-
-
一个promise指定多个成功/失败回调函数,都会调用吗
是的,都会调用
-
改变promise状态和then()执行,谁先谁后
(1)都有可能,一般情况下是先指定回调函数再改变状态,但是也可以先改状态再指定回调
(2)如何先改状态再指定回调?
- 在执行器中直接调用resolve()/rejecte()
- 延迟更长时间才调用then()
(3)什么时候才能执行成功或者失败回调函数
-
当状态改变时
-
promise.then()返回新的promise的结果是由什么决定的?
- 如果返回是非promise值,则返回状态为resolved,值为value的promise对象
- 如果返回是一个新的promise,则此promise的结果就是then()返回的结果
- 如果抛出异常,则返回状态为rejected,值为reason的promise对象
-
promise如何串联多个操作任务
let p = new Promise((resolve, reject) => { setTimeout(() => { resolve('OK') }, 1000) }) p.then((value) => { return new Promise((resolve, reject) => { resolve('success') }) }).then((value) => { console.log(value) }).then(value => { console.log(value); })
输出结果:
-
promise异常穿透
let p = new Promise((resolve, reject) => { setTimeout(() => { resolve('OK') }, 1000) }) p.then((value) => { return new Promise((resolve, reject) => { reject('err') }) }).then((value) => { throw '失败' }).then(value => { console.log(value); }).catch((reason) => { console.warn(reason) }) //输出err
-
如何中断promise链
在回调函数中返回一个pendding状态的promise对象
let p = new Promise((resolve, reject) => { setTimeout(() => { resolve('OK') }, 1000) }) p.then((value) => { console.log(111); //有且只有一种方法 return new Promise(() => { }) }).then((value) => { console.log(222); }).then(value => { console.log(333); }).catch((reason) => { console.warn(reason) }) //输出111
二、Promise的自定义封装
1. 定义执行器函数
function Promise(executor) {
//定义Promise对象的属性
this.PromiseState = 'pending'
this.PromiseResult = null
//保留实例对象的this的值
const self = this
//resolve函数
function resolve(data) {
self.PromiseState = 'fulfilled'
self.PromiseResult = data
}
//reject函数
function reject(data) {
self.PromiseState = 'rejected'
self.PromiseResult = data
}
//同步调用[执行器函数]
executor(resolve, reject)
}
2. 通过throw抛出异常改变状态
function Promise(executor) {
、、、
try {
//同步调用【执行器函数】
executor(resolve, reject)
} catch (e) {
//修改状态为【失败】
reject(e)
}
}
3. 状态只能修改一次
function Promise(executor) {
、、、
//resolve函数
function resolve(data) {
//判断状态
if (self.PromiseState !== 'pending') return;
self.PromiseState = 'fulfilled'
self.PromiseResult = data
}
//reject函数
function reject(data) {
//判断状态
if (self.PromiseState !== 'pending') return;
self.PromiseState = 'rejected'
self.PromiseResult = data
}
、、、
}
4. then方法实现
//添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
//调用回调函数
if (this.PromiseState === 'fulfilled') {
onResolved(this.PromiseResult)
}
if (this.PromiseState === 'rejected') {
onRejected(this.PromiseResult)
}
}
5. 异步任务 then 方法的实现(保存回调函数)
function Promise(executor) {
、、、
//声明保存回调函数的属性
this.callback = {}
//resolve函数
function resolve(data) {
、、、
//执行回调函数
if(self.callback.onResolved){
self.callback.onResolved(data)
}
}
//reject函数
function reject(data) {
、、、
//执行回调函数
if(self.callback.onRejected){
self.callback.onRejected(data)
}
}
、、、
}
//添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
、、、
//执行异步任务时候,保存回调函数
if(this.PromiseState==='pending'){
this.callback = {
onResolved: onResolved,
onRejected: onRejected
}
}
}
6.指定多个回调(callback为数组)
function Promise(executor) {
、、、
//声明保存回调函数的属性
this.callback = []
//保留实例对象的this的值
const self = this
//resolve函数
function resolve(data) {
、、、
//执行回调函数
// if (self.callback.onResolved) {
// self.callback.onResolved(data)
// }
self.callback.forEach(element => {
element.onResolved(data)
});
}
//reject函数
function reject(data) {
、、、
//执行回调函数
// if (self.callback.onRejected) {
// self.callback.onRejected(data)
// }
self.callback.forEach(element => {
element.onRejected(data)
})
}
、、、
}
//添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
、、、
//执行异步任务时候,保存回调函数到callback数组中
if(this.PromiseState==='pending'){
this.callback.push(
{
onResolved: onResolved,
onRejected: onRejected
}
)
}
}
7.改写同步任务then返回结果为promise对象
//添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
//返回一个promise对象
return new Promise((resolve, reject) => {
//调用回调函数
if (this.PromiseState === 'fulfilled') {
try {
//获取回调函数的结果
let result = onResolved(this.PromiseResult)
if (result instanceof Promise) {
//是Promise对象,通过then方法改变状态和值
result.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
//不是Promise对象
resolve(result)
}
} catch (e) {
reject(e)
}
}
if (this.PromiseState === 'rejected') {
try {
//获取回调函数的结果
let result = onRejected(this.PromiseResult)
if (result instanceof Promise) {
//是Promise对象,通过then方法改变状态和值
result.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
//不是Promise对象
resolve(result)
}
} catch (e) {
reject(e)
}
}
//执行异步任务时候,保存回调函数
、、、
}
8.异步任务,改写then返回结果为promise
if(this.PromiseState==='pending'){
//执行异步任务时候,保存回调函数
this.callback.push(
{
onResolved: function () {
try {
let result = onResolved()
if (result instanceof Promise) {
//是promise对象
result.then(v => resolve(v), r => reject(r))
} else {
//不是promise对象
resolve(result)
}
} catch (e) {
reject(e)
}
},
onRejected: function () {
try {
let result = onRejected()
if (result instanceof Promise) {
//是promise对象
result.then(v => resolve(v), r => reject(r))
} else {
//不是promise对象
resolve(result)
}
} catch (e) {
reject(e)
}
},
}
)
}
9. 优化代码
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
return new Promise((resolve, reject) => {
//封装回调函数代码
function callback(type) {
try {
//获取回调函数的结果
let result = type(self.PromiseResult)
if (result instanceof Promise) {
//是Promise对象,通过then方法改变状态和值
result.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
//不是Promise对象
resolve(result)
}
} catch (e) {
reject(e)
}
}
//调用回调函数
if (this.PromiseState === 'fulfilled') {
callback(onResolved)
}
if (this.PromiseState === 'rejected') {
callback(onRejected)
}
if (this.PromiseState === 'pending') {
//执行异步任务时候,保存回调函数
this.callback.push(
{
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
},
}
)
}
})
}
10. catch方法与异常穿透
实现以下功能
let p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('reject')
}, 1000)
})
let res = p.then().then((value) => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason)
})
设置默认回调函数
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
//判断参数,如果不存在回调函数,则设置默认回调函数
if (typeof onRejected !== 'function') {
onRejected = reason => { throw reason }
}
if(typeof onResolved !=='function'){
onResolved = value =>value
}
return new Promise((resolve, reject) => {
、、、
})
}
//添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
11. 实现Promise.resolve()
//添加resolve方法
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v => resolve(v), r => reject(r))
} else {
resolve(value)
}
})
}
12. 实现Promise.all()
//添加all方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
//声明变量
let count = 0
let arr = []
for (i = 0; i < promises.length; i++) {
promises[i].then((value) => {
count++;
arr[i] = value;
if (count === promises.length) {
resolve(arr)
}
}, (reason) => {
reject(reason)
})
}
})
}
13. 实现Promise.race()方法
//添加race方法:谁先改变状态,返回哪个promise对象
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (i = 0; i < promises.length; i++) {
promises[i].then((value) => {
resolve(value)
}, (reason) => {
reject(reason)
})
}
})
}
14. then()是异步执行的
let p1 = new Promise((resolve, reject) => {
// setTimeout(() => { r('ok') }, 1000)
resolve('ok')
console.log(111);
})
p1.then(value => {
console.log(222);
})
console.log(333);
改进方法:让回调函数在定时器内部执行
Promise.prototype.then = function (onResolved, onRejected) {
、、、
return new Promise((resolve, reject) => {
、、、
//调用回调函数
if (this.PromiseState === 'fulfilled') {
setTimeout(() => { callback(onResolved) })
}
if (this.PromiseState === 'rejected') {
setTimeout(() => { callback(onRejected) })
}
、、、
})
}
function Promise(executor) {
、、、
//resolve函数
function resolve(data) {
、、、
setTimeout(() => {
self.callback.forEach(element => {
element.onResolved(data)
});
})
}
//reject函数
function reject(data) {
、、、
setTimeout(() => {
self.callback.forEach(element => {
element.onRejected(data)
})
})
}
}
15. 完整代码
function Promise(executor) {
//定义Promise对象的属性
this.PromiseState = 'pending'
this.PromiseResult = null
//声明保存回调函数的属性
this.callback = []
//保留实例对象的this的值
const self = this
//resolve函数
function resolve(data) {
//判断状态
if (self.PromiseState !== 'pending') return;
self.PromiseState = 'fulfilled'
self.PromiseResult = data
//执行回调函数
// if (self.callback.onResolved) {
// self.callback.onResolved(data)
// }
setTimeout(() => {
self.callback.forEach(element => {
element.onResolved(data)
});
})
}
//reject函数
function reject(data) {
//判断状态
if (self.PromiseState !== 'pending') return;
self.PromiseState = 'rejected'
self.PromiseResult = data
//执行回调函数
// if (self.callback.onRejected) {
// self.callback.onRejected(data)
// }
setTimeout(() => {
self.callback.forEach(element => {
element.onRejected(data)
})
})
}
try {
//同步调用【执行器函数】
executor(resolve, reject)
} catch (e) {
//修改状态为【失败】
reject(e)
}
}
//添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
//判断参数
if (typeof onRejected !== 'function') {
onRejected = reason => { throw reason }
}
if (typeof onResolved !== 'function') {
onResolved = value => value
}
return new Promise((resolve, reject) => {
//封装回调函数代码
function callback(type) {
try {
//获取回调函数的结果
let result = type(self.PromiseResult)
if (result instanceof Promise) {
//是Promise对象,通过then方法改变状态和值
result.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
//不是Promise对象
resolve(result)
}
} catch (e) {
reject(e)
}
}
//调用回调函数
if (this.PromiseState === 'fulfilled') {
setTimeout(() => { callback(onResolved) })
}
if (this.PromiseState === 'rejected') {
setTimeout(() => { callback(onRejected) })
}
if (this.PromiseState === 'pending') {
//执行异步任务时候,保存回调函数
this.callback.push(
{
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
},
}
)
}
})
}
//添加catch方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
//添加resolve方法
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v => resolve(v), r => reject(r))
} else {
resolve(value)
}
})
}
//添加reject方法
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
//添加all方法
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
//声明变量
let count = 0
let arr = []
for (i = 0; i < promises.length; i++) {
promises[i].then((value) => {
count++;
arr[i] = value;
if (count === promises.length) {
resolve(arr)
}
}, (reason) => {
reject(reason)
})
}
})
}
//添加race方法:谁先改变状态,返回哪个promise对象
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (i = 0; i < promises.length; i++) {
promises[i].then((value) => {
resolve(value)
}, (reason) => {
reject(reason)
})
}
})
}
16. class版本
class Promise {
constructor(executor) {
//定义Promise对象的属性
this.PromiseState = 'pending'
this.PromiseResult = null
//声明保存回调函数的属性
this.callback = []
//保留实例对象的this的值
const self = this
//resolve函数
function resolve(data) {
//判断状态
if (self.PromiseState !== 'pending') return;
self.PromiseState = 'fulfilled'
self.PromiseResult = data
//执行回调函数
// if (self.callback.onResolved) {
// self.callback.onResolved(data)
// }
setTimeout(() => {
self.callback.forEach(element => {
element.onResolved(data)
});
})
}
//reject函数
function reject(data) {
//判断状态
if (self.PromiseState !== 'pending') return;
self.PromiseState = 'rejected'
self.PromiseResult = data
//执行回调函数
// if (self.callback.onRejected) {
// self.callback.onRejected(data)
// }
setTimeout(() => {
self.callback.forEach(element => {
element.onRejected(data)
})
})
}
try {
//同步调用【执行器函数】
executor(resolve, reject)
} catch (e) {
//修改状态为【失败】
reject(e)
}
}
then(onResolved, onRejected) {
const self = this
//判断参数
if (typeof onRejected !== 'function') {
onRejected = reason => { throw reason }
}
if (typeof onResolved !== 'function') {
onResolved = value => value
}
return new Promise((resolve, reject) => {
//封装回调函数代码
function callback(type) {
try {
//获取回调函数的结果
let result = type(self.PromiseResult)
if (result instanceof Promise) {
//是Promise对象,通过then方法改变状态和值
result.then(v => {
resolve(v)
}, r => {
reject(r)
})
} else {
//不是Promise对象
resolve(result)
}
} catch (e) {
reject(e)
}
}
//调用回调函数
if (this.PromiseState === 'fulfilled') {
setTimeout(() => { callback(onResolved) })
}
if (this.PromiseState === 'rejected') {
setTimeout(() => { callback(onRejected) })
}
if (this.PromiseState === 'pending') {
//执行异步任务时候,保存回调函数
this.callback.push(
{
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
},
}
)
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(v => resolve(v), r => reject(r))
} else {
resolve(value)
}
})
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
static all(promises) {
return new Promise((resolve, reject) => {
//声明变量
let count = 0
let arr = []
for (i = 0; i < promises.length; i++) {
promises[i].then((value) => {
count++;
arr[i] = value;
if (count === promises.length) {
resolve(arr)
}
}, (reason) => {
reject(reason)
})
}
})
}
static race(promises) {
return new Promise((resolve, reject) => {
for (i = 0; i < promises.length; i++) {
promises[i].then((value) => {
resolve(value)
}, (reason) => {
reject(reason)
})
}
})
}
}
三、async和await
1. async 函数
-
返回值为promise对象
-
内部函数返回值决定Promise对象
async function main() { } console.log(main())
输出:
2. await表达式
-
await右侧一般是promise对象,但是也可以是其他值
-
如果是promise对象,则await返回的是promise成功时的promise.PromiseResult
-
如果是其他值,则直接把此值作为await的返回值
-
await必须写在async函数里面
-
如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
async function main() { let p = new Promise((resolve, reject) => { resolve('ok') }) //1.右侧是promise的情况 let res1 = await p; //2.右侧是其他类型的情况 let res2 = await 20 console.log(res1) console.log(res2) //3.右侧是promise失败的情况 try { let res3 = await Promise.reject('err') } catch (e) { console.log(e); } } main()
输出:
3. async和await结合的实例一:文件读取
拼接文件1、文件2、文件3
//普通写法
const fs = require('fs')
fs.readFile('./resource/1.txt', (err, data1) => {
if (err) throw err
fs.readFile('./resource/2.txt', (err, data2) => {
if (err) throw err
fs.readFile('./resource/3.txt', (err, data3) => {
if (err) throw err
console.log(data1 + data2 + data3);
})
})
})
//async和await结合写法
const fs = require('fs')
const util = require('util')
//将fs.readFile方法的返回值转换为一个promise对象
const mineRead = util.promisify(fs.readFile)
async function main() {
try {
const data1 = await mineRead('./resource/11.txt')
const data2 = await mineRead('./resource/2.txt')
const data3 = await mineRead('./resource/3.txt')
console.log(data1 + data2 + data3);
} catch (e) {
console.log(e);
}
}
main()
4. async和await结合实例二:AJAX
function sendAJAX(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onreadystatechange() = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject(xhr.status)
}
}
}
})
}
async function duanzi() {
const res = await sendAJAX('https://api.apiopen.top/getJoke')
console.log(res);
}