这里写目录标题
- 一、.Promise对象详解
- 1. Promise是什么
- 2. Promise的优点
- 3. 异步编程
- 4. then(onFulfilled, onRejected):
- 5. util.promisify 方法:
- 6. promise的状态改变
- 7.Promise 对象的值
- 8. Promise的基本执行流程
- 9. Promise的API
- 10. Promise中的关键问题
- 二、Promise的自定义封装
- 1. 定义执行器函数
- 2. 通过throw抛出异常改变状态
- 3. 状态只能修改一次
- 4. then方法实现
- 5. 异步任务 then 方法的实现(保存回调函数)
- 6.指定多个回调(callback为数组)
- 7.改写同步任务then返回结果为promise对象
- 8.异步任务,改写then返回结果为promise
- 9. 优化代码
- 10. catch方法与异常穿透
- 11. 实现Promise.resolve()
- 12. 实现Promise.all()
- 13. 实现Promise.race()方法
- 14. then()是异步执行的
- 15. 完整代码
- 16. class版本
- 三、async和await
- 1. async 函数
- 2. await表达式
- 3. async和await结合的实例一:文件读取
- 4. async和await结合实例二:AJAX
一、.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') {onRejected(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 = thisreturn 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)})
//输出
//222
//333
设置默认回调函数
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 = 0let 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 = 0let 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 = 0let 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 20console.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 errfs.readFile('./resource/2.txt', (err, data2) => {if (err) throw errfs.readFile('./resource/3.txt', (err, data3) => {if (err) throw errconsole.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);}