一、 为什么要使用promise
1. 指定回调函数的方式更加灵活:
旧的: 必须在启动异步任务前指定
promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
2. 支持链式调用, 可以解决回调地狱问题
什么是回调地狱? 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调函数执行的条件
回调地狱的缺点? 不便于阅读 / 不便于异常处理
解决方案? promise链式调用
3. Promise中的then中执行 onResolved 函数是微任务,需要放入队列
4. Promise中的then执行,靠之前resolve先改变状态,否则不会放入队列
3跟4很关键,看最后一道面试题,以及练习题
function successCallback(result) {
console.log("声音文件创建成功: " + result);
}
function failureCallback(error) {
console.log("声音文件创建失败: " + error);
}
createAudioFileAsync(audioSettings, successCallback, failureCallback)
const promise = createAudioFileAsync(audioSettings);
setTimeout(() => {
promise.then(successCallback, failureCallback);
}, 3000);
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult)
}, failureCallback)
}, failureCallback)
}, failureCallback)
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 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)
}
}
二、promise — API
- Promise构造函数: Promise (excutor) {}
excutor函数: 同步执行 (resolve, reject) => {}
resolve函数: 内部定义成功时我们调用的函数 value => {}
reject函数: 内部定义失败时我们调用的函数 reason => {}
说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行
2. Promise.prototype.then方法: (onResolved, onRejected) => {}
onResolved函数: 成功的回调函数 (value) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
返回一个新的promise对象
3. Promise.prototype.catch方法: (onRejected) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected)
4. Promise.resolve方法: (value) => {}
value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象
5. Promise.reject方法: (reason) => {}
reason: 失败的原因
说明: 返回一个失败的promise对象
6. Promise.all方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7. Promise.race方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态
三、promise中几个关键性问题?
1、如何改变promise的状态?
(1)resolve(value): 如果当前是pendding就会变为resolved
(2)reject(reason): 如果当前是pendding就会变为rejected
(3)抛出异常: 如果当前是pendding就会变为rejected
2、 一个promise指定多个成功/失败回调函数, 都会调用吗?
当promise改变为对应状态时都会调用
3、改变promise状态和指定回调函数谁先谁后?
(1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2)如何先改状态再指定回调?
①在执行器中直接调用resolve()/reject()
②延迟更长时间才调用then()
(3)什么时候才能得到数据?
①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
4、promise.then()返回的新promise的结果状态由什么决定?
(1)简单表达: 由then()指定的回调函数执行的结果决定
(2)详细表达:
①如果抛出异常, 新promise变为rejected, reason为抛出的异常
②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
5、promise如何串连多个操作任务?
(1)promise的then()返回一个新的promise, 可以开成then()的链式调用
(2)通过then的链式调用串连多个同步/异步任务
6、promise异常传/穿透?
(1)当使用promise的then链式调用时, 可以在最后指定失败的回调,
(2)前面任何操作出了异常, 都会传到最后失败的回调中处理(倒不如说开始都会定义好then/catch函数,等待被执行)
7、中断promise链?
(1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
(2)办法: 在回调函数中返回一个pendding状态的promise对象
Promise 源码实现
(function (window) {
const REJECTED = 'rejected',
RESOLVED = 'resolved',
PENDING = 'pending'
function Promise(excutor){
const that = this
console.log('看看Promise中的this',that)
that.data = undefined
that.status = PENDING
that.callBack = []
function resolve(value) {
if (that.status !== PENDING) {
return
}
that.status = RESOLVED
that.data = value
if (that.callBack && that.callBack.length > 0) {
that.callBack.forEach(callsObj => {
setTimeout(() => {
callsObj.onResolvedcallback(value)
})
})
}
}
function reject(reson) {
if (that.status !== PENDING) {
return
}
that.status = REJECTED
that.data = reson
if (that.callBack && that.callBack.length > 0) {
that.callBack.forEach(callsObj => {
setTimeout(() => {
callsObj.onRejectedcallback(reson)
})
})
}
}
try {
excutor(resolve, reject)
} catch(error) {
reject(error)
}
}
function isPromise(obj) {
if (obj) {
console.log('typeof obj.then', typeof obj.then)
return (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
}
return false
}
Promise.prototype.then = function(onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value
onRejected = typeof onRejected==='function' ? onRejected : reason => {throw reason}
let that = this
console.log('看看then中的this',that)
return new Promise((resolve, reject) => {
function handleCallBack(callBack) {
try {
const result = callBack(that.data)
console.log('94', isPromise(result));
if (isPromise(result)) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
console.log('100', error);
reject(error)
}
}
if (that.status === RESOLVED) {
setTimeout(() => {
handleCallBack(onResolved)
})
} else if (that.status === REJECTED) {
setTimeout(() => {
handleCallBack(onRejected)
})
} else {
that.callBack.push({
onRejectedcallback() {
handleCallBack(onResolved)
},
onResolvedcallback() {
handleCallBack(onResolved)
}
})
}
})
}
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
Promise.resolve = function(value) {
return new Promise((resolve, reject) => {
if (isPromise(value)) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
Promise.reject = function(reason) {
return new Promise((resolve, reject) => {
if (isPromise(reason)) {
reject.catch(reject)
} else {
reject(reason)
}
})
}
Promise.all = function(promises) {
if (promises && promises.length > 0) {
const values = new Array(promises.length)
return new Promise((resolve, reject) => {
promises.forEach((p, index) => {
})
})
return
}
return []
}
window.Promise = Promise
window.isPromise = isPromise
})(window)
Promise 练习题
new Promise((resolve,reject) => {
setTimeout(() => {
reject('123')
})
}).then(
).catch((error) => {
console.log('error: ', error);
})
new Promise((resolve,reject) => {
setTimeout(() => {
reject('123')
})
}).then(
value => {console.log('value1', value)},
reason => {
console.log('reason1', reason)
const promiseResolve = Promise.resolve('hhhhhhh')
return promiseResolve
}, '第一个this'
)
.then(
value => {
console.log('value2', value)
return 'resolve2()执行之后影响谁的结果'
},
reason => {
console.log('reason2', reason)
}, '第二个this'
)
Promise面试题:
一、
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
}).then(() => {
console.log(4)
})
console.log(5)
二、
const first = () => (
new Promise((resolve, reject) => {
console.log(3)
let p = new Promise((resolve, reject) => {
console.log(7)
setTimeout(() => {
console.log(5)
resolve(6)
}, 0)
resolve(1)
})
resolve(2)
p.then((arg) => {
console.log(arg)
})
})
)
first().then((arg) => {
console.log(arg)
})
console.log(4)
三、
setTimeout(() => {
console.log("0")
}, 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")
})