promise前端进阶
一、准备工作
1、区别实例对象跟函数对象
- 函数对象:将函数作为对象使用时
- 实例对象:new 函数生产的对象
function Fn(){} //Fn函数
const fn = new Fn() //Fn是构造函数 fn是实例对象
Fn.prototype //Fn是函数对象
Fn.call({}) //Fn是函数对象
$('#test') //jQuery函数
$.get('/') //jQuery函数对象
总结:点的左边是对象,括号的左边是函数
2、回调函数的分类
同步回调
立即执行,完全执行完了才结束,不会放入回调队列
例子:数组遍历相关的回调函数、promise的excutor函数
// 同步回调
const arr=[1,2,3]
arr.forEach(item =>{
console.log(item)
})
console.log('forEach后')
/*
运行结果:
1
2
3
forEach后
*/
异步回调
不立即执行,会放入回调队列中将来执行
例子:定时器回调、ajax回调、promise的成功失败
// 异步回调
setTimeout(arr=>{
console.log('arr')
},0)
console.log('setTimeout之后')
/*
运行结果:
setTimeout之后
arr
*/
3、error错误处理
错误的类型
- Error:所有错误的父类型
- ReferenceError:引用的变量不存在
- TypeError:数据类型不正确的错误
- SyntaxError:语法语法
捕获错误:try...catch
抛出错误:throw error
错误对象
message属性
:错误相关信息stack属性
:函数调用栈记录信息
二、promise的理解与使用
1、promise是什么
理解
-
抽象表达:
promise是js中异步编程的新的解决方案
-
具体表达:
- promise是一个构造函数
- promise对象用来封装一个异步操作并可以获取其结果
promise的状态改变
-
pending变为resolved
-
pending变为rejected
只有这2种,且一个promise对象只能改变一次无论失败还是成功
成功一般称为value,失败称为reason
工作原理图
使用流程实例
<script>
// 1.创建一个新的promise对象
const p = new Promise((resolve,reject)=>{
// 2.执行异步操作任务
const time = Date.now()//偶数成功,奇数失败
// 3.1如果成功,调用resolve(value)
if(time %2 == 0){
resolve('成功的数据,time='+time)
}else {
// 3.2如果失败,调用reject(reason)
reject('失败的数据,time='+time)
}
})
p.then(
value => {//接受到的成功value数据
console.log('成功的个回调',value)
},
reason =>{//接受到失败的reason数据
console.log('失败的回调',reason)
}
)
</script>
2、为什么用promise
指定回调函数的方式更加灵活
因为没用Promise之前,使用回调函数时,传入的回调函数必须放在前面,放到后边就用不到了,导致得不到数据
-
旧的:说白了原来的方式就是必须在启动异步任务前指定
-
promise:启动异步任务=》返回promise对象=》给promise对象绑定回调函数(甚至可以在异步)
支持链式调用,可以解决回调地狱
回调地狱
回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件
doSomething(function (result) { doSomethingElse(result, function (newResult) { doThirdThing(newResult, function (finalResult) { console.log('Got the final result: ' + finalResult) }, failureCallback) },failureCallback) }, failureCallback)
promise解决回调地狱
一个promise对应一个异步结果
doSomething()
.then( function( result) {
return doSomethingElse(result)
})
.then( function(newResult) {
return doThirdThing( newResult)
})
.then( function(finalResult) {
console.log('Got the final result: ' + finalResult)
})
.catch( failureCallback)
async / await: 回调地狱的终极解决方案
async function request() {
try {
const result = await doSomething()
const newResult = await doSomethingElse(result)
const finalResult = await doThirdThing(newResult)
console.log('Got the final result: ' + finalResult)
} catch (error) {
failureCallback(error)
}
}
3、如何使用promise
API
-
Promise构造函数:
Promise (excutor) {}
-
excutor函数:同步执行(resolve, reject) => {}
-
resolve函数:内部定义成功时我们调用的函数value => { }
-
reject函数:内部定义失败时我们调用的函数reason => {}
说明: excutor 会在Promise内部立即同步回调,异步操作在执行器中执行
Promise.prototype.then方法: ``(onResolved, onRejected) => {}
-
onResolved函数:成功的回调函数(value) => {}
-
onRejected函数:失败的回调函数(reason) => {}
说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调
返回一个新的promise对象
Promise.prototype.catch方法:
(onRejected) => {}`
-
onRejected函数:失败的回调函数(reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected )
Promise.resolve方法: (value) => {}
-
value:成功的数据或promise对象
说明:返回一个成功/失败的promise对象
-
Promise.reject方法: (reason) => {}
-
reason:失败的原因
说明:返回一个失败的promise对象
-
-
Promise.al1方法: (promises) => {}
-
promises:包含n个promise的数组
说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败
Promise.race方法: (promises) => {}
-
promises :
包含n个promise的数组说明:返回一个新的promise,第-” 个完成的promise的结果状态就是最终的结果状态
4、promise的关键问题
如何改变promise 的状态
- resolve:如果当前是pendding就会变为resolved
- reject:如果当前是pendding就会变为rejected
- 抛出异常:如果当前是pendding就会变为rejected
当一个promise指定多个成功、失败回调函数,都会调用吗
当promise改变状态时就会调用
promise.then()返回的新promise的结果状态由什么决定
由then指定的回调函数执行的结果决定
三、手写promise
第一步:搭建框架
-
创建一个
手写promise.js
的js文件来实现promise
-
将这个文件引入一个
自定义promise.html
的文件中去使用
/*
自定义Promise模块
*/
(function (window) {
/*
promise 构造函数
executor :执行器函数(同步执行函数)
*/
function Promise(executor) {
}
/*
Promise原型对象的then()
指定成功失败的回调函数
返回一个新的promise对象
*/
Promise.prototype.then = function (onResolved,onRejected) {
}
/*
Promise原型对象的catch()
指定失败的回调函数
返回一个新的promise对象
*/
Promise.prototype.catch = function (onRejected) {
}
/*
Promise函数对象resolve方法
返回指定结果的一个成功的promise
*/
Promise.resolve = function (value) {
}
/*
Promise函数对象reject方法
返回一个指定reason的失败的promise
*/
Promise.reject = function (reason) {
}
/*
Promise函数对象all方法
返回一个promise,只有当所有promise都成功时才成功,否则失败
(只要有一个失败,就失败)
*/
Promise.all = function (promises) {
}
/*
Promise函数对象race方法
返回一个promise,结果由第一个完成的promise来决定
*/
Promise.race = function (promises) {
}
// 向外暴露promise函数
window.Promise = Promise
})(window)
第二步:搭建executor
执行器函数
自定义promise.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义promise</title>
</head>
<body>
<script src="手写promise.js"></script>
<script>
new Promise((resolve,reject)=>{
resolve(1) //value
reject(2) //reason
})
</script>
</body>
</html>
自定义promise.js
将执行器函数简单封装下
function Promise(executor) {
this.status = 'pending' //给promise对象指定status属性,初始值为pending
this.data = undefined //给promise对象指定一个用于存储结果数据的属性
this.callbacks = [] //每个元素的结果:{onResolved(){},onRejected(){}}
function resolve(value) {
//如果当前状态不是pending,直接结束
if (this.status !== 'pending') {
return
}
//将状态改为resolved、
this.status = 'resolved'
//保存value数据
this.data = value
//如果有待执行callback函数,立即异步执行回调函数onResolved
if (this.callbacks.length > 0) {
setTimeout(() => {//放入队列中执行所有成功的回调
this.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
})
})
}
}
function reject(reason) {
//如果当前状态不是pending,直接结束
if (this.status !== 'pending') {
return
}
//将状态改为rejected
this.status = 'rejected'
//保存value数据
this.data = reason
//如果有待执行callback函数,立即异步执行回调函数onRejected
if (this.callbacks.length > 0) {
setTimeout(() => {//放入队列中执行所有成功的回调
this.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
})
})
}
}
// 立即同步执行executor
try {
executor(resolve, reject)
} catch (error) {//如果执行器抛出异常,promise对象变为rejected状态
reject(error)
}
}
第三步:优化executor
执行器跟简单实现then()
方法
function Promise(executor) {
// 将当前promise对象保存起来
const self = this
self.status = 'pending' //给promise对象指定status属性,初始值为pending
self.data = undefined //给promise对象指定一个用于存储结果数据的属性
self.callbacks = [] //每个元素的结果:{onResolved(){},onRejected(){}}
function resolve(value) {
//如果当前状态不是pending,直接结束
if (self.status !== 'pending') {
return
}
//将状态改为resolved、
self.status = 'resolved'
//保存value数据
self.data = value
//如果有待执行callback函数,立即异步执行回调函数onResolved
if (self.callbacks.length > 0) {
setTimeout(() => {//放入队列中执行所有成功的回调
self.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
})
})
}
}
function reject(reason) {
//如果当前状态不是pending,直接结束
if (self.status !== 'pending') {
return
}
//将状态改为rejected
self.status = 'rejected'
//保存value数据
self.data = reason
//如果有待执行callback函数,立即异步执行回调函数onRejected
if (self.callbacks.length > 0) {
setTimeout(() => {//放入队列中执行所有成功的回调
self.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
})
})
}
}
// 立即同步执行executor
try {
executor(resolve, reject)
} catch (error) {//如果执行器抛出异常,promise对象变为rejected状态
reject(error)
}
}
/*
Promise原型对象的then()
指定成功失败的回调函数
返回一个新的promise对象
*/
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
//假设当前状态还是pending状态,将回调函数保存起来
self.callbacks.push({
onResolved,
onRejected
})
}
第四步:简单构建then()
方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this
if (self.status === PENDING) {
//假设当前状态还是pending状态,将回调函数保存起来
self.callbacks.push({
onResolved,
onRejected
})
} else if (self.status === RESOLVED) {
setTimeout(() => {
/*
1、如果抛出异常,return promise就会失败,reason就是error
2、如果回调函数执行返回非promise,return的promise成功,value就是返回的值
3、如果回调函数返回的是promise,return的promise结果就是这个promise的结果
*/
try {
const result = onResolved(self.data)
// 3、如果回调函数返回的是promise,return的promise结果就是这个promise的结果
if (result instanceof Promise) {
result.then(
value => resolve(value),//当result成功,让return的promise也成功
reason => reject(reason)//当result失败,让return的promise也失败
)
} else {
//2、如果回调函数执行返回非promise,return的promise成功,value就是返回的值
resolve(result)
}
} catch (error) {
// 1、如果抛出异常,return promise就会失败,reason就是error
reject(error)
}
});
} else { //'rejected'
setTimeout(() => {
onRejected(self.data)
});
}
// 返回一个新的promise对象
return new Promise((resolve,reject) => {
})
}