promise
准备
主要参考:【尚硅谷Promise教程(promise前端进阶必学)-哔哩哔哩】https://b23.tv/JDbM5b 和 MDN文档
函数对象和实列对象
<script>
function Fn() { } //fn是函数
const fn = new Fn() //Fn是构造函数,通过new调用的函数时构造函数,fn是实列对象(简称对象)
Fn.bind({}) // Fn是函数对象,将一个函数当作对象使用时称为函数对象
</script>
两种类型的回调函数
回调函数:我定义的函数,我没有调用这个函数,但是最终执行了
- 同步回调:立即执行,完全执行完了才结束,不会放入回调队列中
<script>
const arr = [1, 3, 5]
arr.forEach(item => {
console.log(item)
})
console.log('forEach()之后') // 最终输出 1,3,5,'forEach()之后'
//forEach()中的函数时同步回调函数
</script>
- 异步回调:放入队列中将来执行
<script>
setTimeout(()=>{
console.log('timeout callback()')
})
console.log('setTimeout()之后') //最终输出 'setTimeout()之后','timeout callback()'
//setTimeout的回调时异步回调函数
</script>
关于回调的练习
<script>
function run2(a) {
return function fn(fn) {
function num1(n1) {
return 2 * n1
}
function num2(n2) {
return 2 * n2
}
return function () {
return a * fn(num1, num2)
}
}
}
let a = run2(3)(function (num1, num2) {
return num1(1) + num2(2)
})()
console.log(a) // 18
</script>
JS错误处理
常见的内置错误的类型:
-
Error
- ReferenceError
<script> console.log(a) </script>
页面输出如下

- TypeError:数据类型不正确
<script> let b = null console.log(b.fn) </script>
页面输出如下

- RangeError:
<script> function fn() { fn() } fn() </script>
页面输出如下

- SyntaxError:语法错误
<script> const a = """" </script>
页面输出如下

- ReferenceError
错误处理
-
捕获错误 try...catch
<script> try { const a = null console.log(a.d()) } catch (error) { console.dir(error) } //如果try中出错,则会进入catch中 </script>
-
抛出错误 throw new Error() 让下一级处理
<script> function something() { if (Date.now() % 2 === 1) { console.log('可以执行任务') } else { throw new Error('不符合执行条件') } } try { something() } catch (error) { alert(error) } </script>
Promise
Promise是什么
理解
抽象表达:
- Promise是JS中进行异步编程的新的解决方案(原来的解决方案是纯回调方式)
具体表达:
- 从语法上来说是个构造函数
- 从功能上来说,Promise对象用来分装一个异步操作并可以获取其结果
Promise 的状态以及状态的改变
Promise的状态
每个 Promise 都会先是处于进行中(pending)的状态,此时操作尚未完成,所以它也是未处理(unsettled)的;一旦异步操作执行结束,Promise则变为已处理(settled)的状态。操作结束后,Promise 可能会进入到以下两个状态中的其中一个:
- Fulfilled:Promise异步操作成功完成。
- Rejected:由于程序错误或一些其他原因,Promise 异步操作未能成功完成。
Promise状态的改变
-
pending >>> fulfilled
-
pending >>> rejected
说明:只有这两种变化,而且一个Promise对象只能改变一次,无论标为成功还是失败,都会有一个结果数据,成功的数据一般称为value,失败的结果数据一般称为reason
Promise的基本流程

Promise基本使用
<script>
//1.创建一个新的promise对象,Promise构造函数的参数是个函数
const p = new Promise((resolve, reject) => {//执行器函数,执行器函数是同步回调
// 2. 执行异步操作任务
setTimeout(() => { //如果当前事件是偶数就代表成功,否则就是代表失败
const time = Date.now()
if (time % 2 === 0) {
//3.1 如果成功了,调用resolve(value)
resolve('成功的数据,time=' + time)
} else {
//3.2 如果失败了,调用reject(reason)
reject('失败的数据,time=' + time)
}
}, 1000);
})
p.then(
value => { //接收得到成功的value数据 onResolved
console.log('成功的回调' + value)
},
reason => { //接收得到失败的reason数据 onRejected
console.log('失败的回调' + reason)
}
)
</script>
为什么使用Promise
1.Promise指定回调函数更加灵活
-
纯回调的方式解决异步操作时指定回调函数必须在启动异步任务前指定
-
Promise:启动异步任务 >>> 返回promise对象 >>> 给promise对象绑定回调函数(甚至可以在异步任务完成以后指定)
<script>
//纯回调的方式
function doSomething1(num, cb) {
setTimeout(() => {
num += 1
console.log(num)
cb(num)
}, 1000);
}
function doSomething2(num) {
setTimeout(() => {
num += 1
console.log(num)
}, 1000);
}
doSomething1(0, doSomething2) //先指定了回调函数,才启动异步任务
//1.创建一个新的promise对象
const p = new Promise((resolve, reject) => {//执行器函数,执行器函数是同步回调
// 2. 执行异步操作任务
setTimeout(() => { //如果当前事件是偶数就代表成功,否则就是代表失败
const time = Date.now()
if (time % 2 == 0) {
//3.2 如果失败了,调用reject(reason)
reject('失败的数据,time=' + time)
} else {
//3.1 如果成功了,调用resolve(value)
resolve('成功的数据,time=' + time)
}
}, 1000);
})
setTimeout(() => {
p.then(
value => { //接收得到成功的value数据 onResolved
console.log('成功的回调' + value)
},
reason => { //接收得到失败的reason数据 onRejected
console.log('失败的回调' + reason)
}
)
}, 5000);
</script>
2.支持链式调用,可以解决回调地狱问题
-
什么是回调地狱?回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件;回调地狱涉及多个串联的异步操作,而且是串联执行的,比如有三个异步操作,异步操作2是依赖异步操作1的结果,异步操作3依赖异步操作2的结果,这样就会在异步操作1的回调函数种嵌套异步操作2的
-
回调地狱的缺点,不便于阅读,不便于异常处理
-
解决方案
-
promise链式调用
-
终极解决方案:asyns/await
-
<script>
//回调地狱涉及多个串联的异步操作,而且是串联执行的,,比如有三个异步操作,异步操作2是依赖异步操作1的结果,异步操作3依赖异步操作2的结果
doSomething1(function (value) {
doSomething2(function (result1) {
doSomething3(function (result2) {
console.log('got ths final result' + result3)
}, failureCallback)
}, failureCallback)
}, failureCallback)
//使用promise的链式调用解决回调地狱,doSomething返回一个promise对象
doSomething1()
.then(function (result1) {
return doSomething2(result1)
})
.then(function (result2) {
return doSomething3(result2)
})
.then(function (result13) {
console.log('Got the final result:' + result13)
})
.catch(failureCallback)
//async/await
async function request() {
try {
const result1 = await doSomething1()
const result2 = await doSomething2(result1)
const result3 = await doSomething3(result2)
console.log('Got the final result:' + result13)
} catch (error) {
failureCallback(error)
}
}
</script>
API
-
Promise 构造函数:Promise(excutor)
-
excutor 函数:执行函数 (resolve, reject) => {},excutor是同步执行函数
-
resolve 函数:内部定义成功时调用的函数 resolve(value)
-
reject 函数:内部定义失败时调用的函数 reject(reason)
-
说明:excutor 是执行器,会在 Promise 内部立即同步回调,异步操作 resolve/reject 就在 excutor 中执行
-
静态方法
Promise.resolve(value)
-
value:可以是一般值和promise对象
-
返回值:
-
value是一般值 >>> Promise.resolve(value)返回一个成功的promise,返回的promise的值就是value
-
value是promise对象 >>> Promise.resolve(value)返回这个promise本身(value)
-
Promise.reject(reason)
-
reason:是一般值
-
返回值:一个失败的promise对象,失败的值就是参数reason
Promise.all(promises)
-
promises:是一个数组,数组每一项可以是promise或者一般值(数值,字符串undefined,null),一般值都认为是成功的promise(成功的值就是这个一般值)
-
返回值:返回值是一个promise对象,promises中promise都成功则Promise.all(promises)返回的promise就是成功的
<script> /* 当promises中有失败的promise时(不论几个), Promise.all(values)返回最先失败的promise对象; */ const p11 = new Promise((resolve, reject) => { setTimeout(() => { reject(1) }, 2000); }) const p21 = Promise.reject(2) const p31 = Promise.resolve(3) const pAll1 = Promise.all([p11, p21, p31]) //参数是由promise对象组成的数组 pAll1.then(value => { console.log(value) }, reason => { console.log(reason) }) //最终输出 2 /* 当values中promise都成功时,Promise.all(values)返回一个成功的promise对象, 这个返回的promise对象的成功值是由promises中的promise的值组成的数组,这个数组的 每一项顺序是和promises中的promise一致 */ const p12 = new Promise((resolve, reject) => { setTimeout(() => { resolve(1) }, 2000); }) const p22 = Promise.resolve(2) const p32 = Promise.resolve(3) const pAll2 = Promise.all([p12, p22, p32]) //参数是由promise对象组成的数组 pAll2.then(values => { console.log(values) }, reason => { console.log(reason) }) //最终输出 [1,2,3] </script>
Promise.race(promises)
-
promises:是一个由promise对象组成的数组
-
返回值:返回值是一个promise对象,这个promise状态由promises中最先有结果的promise的状态决定
实列方法
Promise.prototype.then(onResolved, onRejected)
p.then((value) => {},(reason) => {})
-
1)onResolved 函数:成功的回调函数 (value) => {}
-
2)onRejected 函数:失败的回调函数 (reason) => {}
-
.then(onResolved,onResolved)方法的返回值: 返回一个promise,这个promise的状态和值由onResolved/onRejected函数的执行结果决定,以onResolved为例,如果执行结果为:
-
无返回值:.then()返回成功的promise,值是undefined
-
返回值一个值:.then()返回一个成功的promise,值就是onResolved/onResolved函数中返回的值
-
返回一个promise:.then()返回的promsie值和状态由onResolved/onResolved函数中返回的promise决定,如果onResolved/onResolved函数返回一个pending状态的promise则 .then() 也返回一个pending状态的promise
-
抛出异常:.then 返回的 失败的Promise,值是抛出的异常
-
说明:.then()是同步执行的,onResolved和onRejected都是异步回调函数,会放到微任务中执行,当p.then()中p的状态确定是成功还是失败后,onResolved/onRejected就会放入到微任务中,而且onResolved和onRejected只会执行一个
Promise几个关键问题
如何改变promise的状态
-
resolve(value):pending >>> fulfilled
-
reject(reason):pending >>> rejected
-
抛出异常throw new Error():pending >>> rejected
<script>
const p = new Promise(() => {
// throw new Error('出错了')
throw 3 //语法上可以 throw 任何东西
})
p.then(
value => { },
reason => {
console.log(reason)
}
)
</script>
一个promise指定了多个成功/失败的回调函数,当promise改变时对应状态的回调函数都会执行
<script>
const p = Promise.resolve('promsie')
p.then(
value => {
console.log('我是第一个' + value + '的回调函数')
}
)
p.then(
value => {
console.log('我是第二个' + value + '的回调函数')
}
)
//后台会输出 '我是第一个promsie的回调函数' 和 '我是第二个promsie的回调函数'
</script>
改变 promise 状态和指定回调函数谁先谁后?
-
先指定回调函数后改变状态
<script> new Promise((resolve, reject) => { setTimeout(() => { resolve(1) // 后改变状态(同时指定数据) }, 1000); }).then( //先指定回调函数,保存当前指定的回调函数 value => { }, reason => { } ) </script>
-
先改变状态后指定回调函数
<script> new Promise((resolve, reject) => { resolve(1) // 先改变状态(同时指定数据) }).then( //后指定回调函数 value => { }, reason => { } ) const p = new Promise((resolve, reject) => { setTimeout(() => { resolve(1) // 先改变状态(同时指定数据) }, 1000); }) setTimeout(() => { p.then( // 后指定回调函数 value => { }, reason => { } ) }, 1100); </script>
promise如何串连多个任务(同步任务或异步任务)
-
1.promise 的 then() 返回一个新的 promise,可以并成 then() 的链式调用
-
2.通过 then 的链式调用串联多个同步/异步任务
new Promise((resolve, reject) => { setTimeout(() => { console.log('执行任务1(异步)') resolve(1) }, 1000) }).then( value => { console.log('任务1的结果', value) console.log('执行任务2(同步)') return 2 // 同步任务直接return返回结果 } ).then( value => { console.log('任务2的结果', value) return new Promise((resolve, reject) => { // 异步任务需要包裹在Promise对象中 setTimeout(() => { console.log('执行任务3(异步)') resolve(3) }, 1000) }) } ).then( value => { console.log('任务3的结果', value) } ) // 执行任务1(异步) // 任务1的结果 1 // 执行任务2(同步) // 任务2的结果 2 // 执行任务3(异步) // 任务3的结果 3
promise异常穿透 .catch()
说明:
-
失败的结果是一层一层处理下来的,最后传递到 catch 中
<script> new Promise((resolve, reject) => { reject(1) }).then( value => { console.log('onFulFilled1', value) } ).then( value => { console.log('onFulFilled2', value) } ).catch( reason => console.log('onRejected', reason) ) //最终输出 onRejected 1 //以上代码中then中都没有处理异常,相当于以下代码 new Promise((resolve, reject) => { reject(1) }).then( value => { console.log('onFulFilled1', value) }, reason => { //或者reason => Promise.reject(reason) throw reason } ).then( //后指定回调函数 value => { console.log('onFulFilled2', value) }, reason => { throw reason } ).catch( reason => console.log('onRejected', reason) ) </script>
-
前面任何操作出了异常,都会传到最后失败的回调中处理
<script> new Promise((resolve, reject) => { reject(1) }).then( value => { console.log('onFulFilled1', value) } ).then( value => { console.log('onFulFilled2', value) }, reason => { console.log(reason) } ) //最终输出--1 </script>
中断promise链
-
需求: 当使用 promise 的 then 链式调用时,在中间中断,不再调用后面的回调函数
-
办法: 在回调函数中返回一个 pending 状态的 promise 对象
<script> new Promise((resolve, reject) => { //resolve(1) reject(1) }).then( value => { console.log('onResolved1()', value) return 2 } ).then( value => { console.log('onResolved2()', value) return 3 } ).then( value => { console.log('onResolved3()', value) } ).catch( reason => { console.log('onRejected1()', reason) } ).then( value => { console.log('onResolved4()', value) }, reason => { console.log('onRejected2()', reason) } ) // onRejected1() 1 // onResolved4() undefined //为了在 catch 中就中断执行,可以这样写 new Promise((resolve, reject) => { //resolve(1) reject(1) }).then( value => { console.log('onResolved1()', value) return 2 } ).then( value => { console.log('onResolved2()', value) return 3 } ).then( value => { console.log('onResolved3()', value) } ).catch( reason => { console.log('onRejected1()', reason) return new Promise(() => {}) // 返回一个pending的promise } ).then( value => { console.log('onResolved4()', value) }, reason => { console.log('onRejected2()', reason) } ) // onRejected1() 1 </script>
手写Promise
(function (window) {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function P(exctor) {
const self = this
self.status = PENDING
self.data = undefined
self.callbacks = [] // 每个单元的结构:{onResolved(){},onRejected(){}}
function resolve(value) {
//如果当前状态不是 pending 直接结束
if (self.status !== PENDING) return
self.status = RESOLVED
self.data = value
//如果有待执行的callbacks函数,立即执行异步回调函数
if (self.callbacks.length > 0) {
setTimeout(() => { //放入队列中执行所有成功的回调
self.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
});
});
}
}
function reject(reason) {
//如果当前状态不是 pending 直接结束
if (self.status !== PENDING) return
self.status = REJECTED
self.data = reason
//如果有待执行的callbacks函数,立即执行异步回调函数
if (self.callbacks.length > 0) {
setTimeout(() => { //放入队列中执行所有成功的回调
self.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
});
});
}
}
//立即同步执行exctor,如果执行器函数中 抛出异常 则promise变为rejected状态
try {
exctor(resolve, reject)
} catch (error) {
reject(error)
}
}
/*
then:指定成功和失败的回调,返回一个promsie
*/
P.prototype.then = function (onResolved, onRejected) {
//向后传递成功的value
onResolved = typeof onResolved === 'function' ? onResolved : value => value
//实现异常穿透,指定默认的失败的回调
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
const self = this
//返回一个新的promise,返回的promise的结果由onResolved/onRejected执行结果决定
return new P((resolve, reject) => {
function handle(callback) {
/*
执行指定的回调函数
根据执行的结果改变 .then 返回的promise的状态和结果
*/
try {
const result = callback(self.data)
if (result instanceof P) {
result.then(
value => {
resolve(value)
},
reason => {
reject(reason)
}
)
// result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
if (self.status === PENDING) {
//当前状态还是pending,将回调函数保存起来
self.callbacks.push({
onResolved: function (value) {
handle(onResolved)
},
onRejected: function (reason) {
handle(onRejected)
}
})
} else if (self.status === RESOLVED) {
//当前状态还是resolve,异步执行onResolved并改变 .then 返回p的状态
setTimeout(() => {
handle(onResolved)
})
} else {
setTimeout(() => {
handle(onRejected)
})
}
})
}
/*
catch:指定失败的回调,返回一个promsie
*/
P.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
/*
resolve:返回一个成功的promsie,成功的值是value
*/
P.resolve = function (value) {
//
return new P((resolve, reject) => {
if (value instanceof P) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
/*
reject:返回一个失败的promsie,失败的值是reason
*/
P.reject = function (reason) {
//返回失败的promise
return new P((resolve, reject) => {
reject(reason)
})
}
/*
all:返回一个promsie,只有当所有的P都成功时才成功,否则只有有一个失败就失败
*/
P.all = function (Ps) {
const values = new Array(Ps.length)
let resolvedCount = 0
return new P((resolve, reject) => {
Ps.forEach((p, index) => {
P.resolve(p).then(
value => {
resolvedCount++
values[index] = value
if (resolvedCount === Ps.length
) {
resolve(values
)
}
},
reason => {
reject(reason)
}
)
})
})
}
/*
race:返回一个promise,其值看第一个完成的P决定
*/
P.race = function (Ps) {
return new P((resolve, reject) => {
Ps.forEach((p, index) => {
P.resolve(p).then(
value => {
resolve(value)
},
reason => {
reject(reason)
}
)
})
})
}
//返回一个promise,它在指定的事件后才确定结果
P.resolveDelay = function (value, time) {
//
return new P((resolve, reject) => {
setTimeout(() => {
if (value instanceof P) {
value.then(resolve, reject)
} else {
resolve(value)
}
}, time);
})
}
//
P.rejectDelay = function (reason, time) {
setTimeout(() => {
//返回失败的promise
return new P((resolve, reject) => {
reject(reason)
})
}, time);
}
//向外暴露Promise函数
window.P = P
})(window)
async & await
async
说明:
-
async 右边是一个函数
-
async 关键字会将右边函数的执行结果包装成一个promise对象,这个promise对象的值和状态由右边的函数的返回值决定
-
右边函数无返回值:async 返回成功的promise,值是undefined
-
右边函数返回值一个值:返回一个成功的promise,值就是该返回的值
-
右边函数返回一个promise:返回该promise
-
抛出异常:返回的 失败的Promise,值是抛出的异常
说明: 和 .then() 的返回值规则一样
<script > async function fn() { //返回非promise类型的则 async函数的返回值 就是一个成功的promise return 2; //reslut是一个成功的promise,值是2 //抛出错误,返回结果一个是失败的promise throw new Error('出错拉') //reslut是一个失败的promise //返回promise类型 return new Promise((resolve, reject) => { resolve('你好') // reslut是一个成功的promise,值就是 '你好' reject('再见') // reslut是一个失败的promise,值就是 '再见' }) } const result = fn() console.log(result) </script> -
await
说明:
-
await 必须写在async函数中
-
await 右侧是表达式,可以是promise对象,也可以是非promise对象
-
await 返回结果
-
右侧是表达式是非promise对象,返回该表示本身
-
右侧是表达式是promise对象,await可以返回成功的promise值,失败的promise值需要通过try...catch接收
<script type="module"> const p = new Promise((resolve, reject) => { // resolve('成功的值09') reject('失败的错误08') }) const q = function fn() { } async function main() { let dataQ = await q console.log(dataQ); //输出--- ƒ fn() { };;右侧是表达式是非promise对象,返回该表示本身 try { let dataP = await p console.log(dataP); //若果p的执行结果是成功则,输出---成功的值09 } catch (error) { console.log(error); //若果p的执行结果是失败则,输出---失败的错误08,而且p是失败的promise时,失败的值只能通过try...catch接收,await只能接收成功promise的值 } } const result = main() </script> -
队列

分类
-
宏任务:定时器回调,DOM事件回调,ajax回调
-
微任务:promise的回调,mutationObserver的回调
执行规则
-
js引擎首先必须先执行所有的初始化同步任务代码
-
每次准备取出一个宏任务执行前,都要将所有的微任务一个一个取出来执行
-
fn().then(onResolved,onRejected)中 .then()是同步调用执行的,onResolved/onRejected回调函数是异步调用执行的
-
.then(onResolved,onRejected)中, .then()返回的promise状态取决于onResolved/onRejected的执行结果
-
fn().then(onResolved,onRejected)中onResolved(成功的回调)/onRejected(失败的回调)是否放入微队列中取决于fn()返回的promise状态是否是成功/失败,如果fn()的promise是pending状态则onResolved/onRejected不放入微队列
-
.
<script> setTimeout( () => { console.log(0) } ); new Promise( (resolve, reject) => { console.log(1) resolve() } ).then( () => { console.log(2) new Promise((resolve, reject) => { console.log(3) resolve() }).then(() => { console.log(4) }).then(() => { console.log(5) }) } ).then( () => { console.log(6) } ) new Promise((resolve, reject) => { console.log(7) resolve() }).then(() => { console.log(8) }) // 最终输出结果顺序:1 7 2 3 8 4 6 5 0 </script>
new Promise( (resolve, reject) => { console.log(1) resolve(2) } ).then( (value) => { console.log(3) new Promise((resolve, reject) => { console.log(4) resolve(value) }).then((value) => { console.log(value + 3) //5 return value + 3 }).then((value) => { console.log(value + 4) // 9 }) } ).then( (value) => { console.log(value) // undefined } ) //以上代码最终输出: 1 3 4 5 undefined 9
//以下代码最终输出:1 3 4 5 10 9
const one = new Promise((resolve, reject) => {
console.log(1)
resolve(2) // resolve()函数是同步执行的,将promise的状态改为成功,值改为 2
}).then(value => { //第1个then函数
console.log(3)
const two = new Promise((resolve, reject) => {
console.log(4)
resolve(value)
}).then(value => { //第one个then函数
console.log(value + 3) //5
return value + 3
}).then(value => { //第two个then函数
console.log(value + 4) // 9
})
return 10
}).then(value => { //第2个then函数
console.log(value)
})
// 1.先执行
console.log(1)
resolve(2) //这句话执行完promise的状态变为成功
//2.然后执行 第一个 .then() 函数 并将这个then函数指定的回调函数放入微队列
//因为new Promise生成的promise状态已经确定
//3. 执行 第二个 .then() 函数 这个then函数指定的回调函数不放入微队列 因为第一
//个then函数返回的promise状态还没有确定
//4. 执行微队列中任务 第一个 .then()指定的回调函数
//执行
console.log(3)
console.log(4)
resolve(value)---- //这句话执行完promise的状态变为成功
//执行 第 one 个 .then()函数 并将这个then函数指定的回调函数放入微队列
value => {
console.log(value + 3) //5
return value + 3
}
//执行 第 two 个 .then() 函数 这个then函数指定的回调函数不放入微队列 因为第
//one 个then函数返回的promise状态还没有确定
//执行 return 10 这句话执行完之后 将第二个then函数指定的回调函数放入微队列中
//5.执行微队列中任务 第 one 个 .then()指定的回调函数
//执行
console.log(value + 3) //5
return value + 3---这句话执行完将第 two 个 .then()指定的回调函数放入微队列中
//6.执行微队列中任务 第2个 .then()指定的回调函数
//7.执行微队列中任务 第two个 .then()指定的回调函数

浙公网安备 33010602011771号