1. 实例对象与函数对象的区别
函数对象:将函数作为对象使用时,简称为函数对象
实例对象:new 函数产生的对象,简称为对象
function Fn(){ // Fn函数
}
const fn = new Fn() // Fn 此时是构造函数 fn 是实例对象
console.log(Fn.prototype) // Fn 是函数对象
Fn.call({}) // Fn是函数对象
$('#test') // jQuery 函数
$.get('/text') // jQuery 函数对象
function Persion(params){
}
2. 两种类型的回调函数
- 同步回调
理解:立即执行,完全执行完了才结束,不会放到回调队列中去
例子:数组遍历相关的回调函数/Promise的excutor函数
const arr = [1,3,5]
arr.foreach(item => { // 同步回调函数
console.log(item)
})
console.log('foreach()之后')
- 异步回调
理解:不会立即执行,会放入回调队列中将来执行
例子:定时器回调/ ajax回调/ Promise的成功|失败的回调
setTimeout(()=>{
console.log('timeout callback()')
},0)
console.log('setTimeout()之后')
3. JS 的 Error 处理
-
错误的类型
- Error : 所有错误的父类型
- ReferenceError : 引用的变量不存在
- TypeError:数据类型不正确
- RangeError:数据值不在其所允许的范围内
- SyntaxError:语法错误
以上这些错误类型相信大家都见过,这里不再使用代码演示
-
错误处理
- 捕获错误: try ... catch
- 抛出错误:throw error
try { let d console.log(d.xxx) }catch (e){ console.log(e.message) } // 控制台 打印Cannot read property 'xxx' of undefined 不会影响后续代码的执行 console.log(1) // 1
主动抛出错误
function doSomething(){ if(Date.now()%2===1){ console.log('当前时间为奇数,可执行任务') }else{ throw new Error('当前时间为偶数,无法执行任务') } } // 错误有执行者去处理 try{ doSomething(); }catch(e){ alret(e.message) } // 弹窗 当前时间为偶数,无法执行任务
-
错误对象
- message属性:错误相关信息
- stack 属性:函数调用栈记录信息
4. promise 的理解与使用
-
promise 的理解
- 抽象表达:Promise是JS中进行异步编程的新的解决方案(旧的是纯回调式解决方案)
- 具体表达:
- 从语法上来讲:Promise是一个构造函数
- 从功能上来说:promise是一个用来封装一个异步操作并且可以获取其结果的对象
-
promise 的状态的改变
- pending 变为 resolved (执行了 resolve 函数)
- pending 变为 rejected (执行了 reject 函数)
说明:只有这2种,且一个promise对象只能改变一次无论变为成功还是失败,都会有一个结果数据,成功的结果数据一般称为vlaue,失败的结果数据一般称为reason
- promise 的基本流程
// 创建一个新的 promise 对象
const p = new Promise((resolve, reject) => { // 执行器函数
// 开始执行异步操作
setTimeout(() => {
const time = Date.now() // 当前时间为偶数就代表成功
if (time % 2 === 0) {
// 成功则调用 resolve(value)
resolve('成功的回调,time = ' + time)
} else {
// 失败则调用 reject(reason)
reject('失败的回调,time=' + time)
}
}, 1000)
})
p.then(
value => { // 接收得到成功的value数据 onResolved
console.log('成功的回调', value)
},
reason => { // 接收得到失败的reason数据 onRejected
console.log('失败的回调', reason)
}
)
-
为什么要使用promise
-
指定的回调函数的方式更加灵活
- 旧的方式:回调函数必须在启动异步任务前指定
// 成功的回调 function successCallback(result) { console.log('声音文件创建成功' + result) } // 失败的回调 function failureCallback(error) { console.log('声音文件创建失败' + error) } // 使用纯回调函数 createAudioFailAsync(audioSettings, successCallback, failureCallback)
- promise:启动异步任务 => 返回 promise 对象 => 给 promise 对象绑定回调函数 (甚至可以在异步任务结束后指定/多个)
const promise = createAudioFileAsync(audioSettings) setTimeout(() => { promise.then(successCallback, failreCAllback) }, 3000)
-
支持链式调用,可以解决回调地狱的问题
- 什么是回调地狱
回调函数的嵌套调用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件
- 不便于阅读
- 不便于异常的处理
回调地狱
doSomething(function (result) { doSomethingelse(result, function (newresult) { doThirdThing(newresult, function (finalResult) { console.log('Got the final result' + finalResult) }, failureCallback) }, failureCallback) }, failureCallback) // 纯回调函数的回调地狱
使用 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 newResut = await doSomethingElse(result) const finalResult = await doThirdThing(newResut) console.log('Got the final result:' + finalResult) }catch (error){ failureCallback(error) } } // 使用async/await 没有回调函数
-
-
promise 具体语法使用
-
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,onRejeccted)
-
Promise.resolve方法:(value) => {}
- value:成功的数据或者promise对象
说明:返回一个成功或失败的promise对象
-
Promise.reject 方法:(reason)=>{}
- reason:失败的原因
说明:返回一个失败的promise对象
以上 4 5 两条只是提供了创建失败或成功的promise对象的简洁的语法罢了
-
Promise.all 方法:(promises) => {}
- promise:包含n个promise的数组
说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败
-
Promise.race 方法:(promise) => {}
- promise:包含n个promise的数组
说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态
-
简单的使用例子
new Promise((resolve, reject) => {
setTimeout(function () {
resolve('成功的回调')
// reject('失败的回调')
}, 1000)
}).then(value => {
console.log('onResolved1()', value)
}).catch(
reason => {
console.log('onRejected1()1',reason)
}
)
// 在执行器函数里面调用成功或失败的回调函数
// 产生一个成功值为1的promise对象
const p1 = new Promise((resolve, reject) => {
resolve(1)
})
// 上面的语法糖
const p2 = Promise.resolve(2) // 产生一个成功并且结果为2的promise对象
const p3 = Promise.reject(3) // 产生一个是失败并且原因为3的promise对象
p1.then(value => {console.log(value)})
p2.then(value=>{console.log(value)})
p3.then(null,reson=>{console.log(reason)})
const pAll = Promise.all([p1,p2,p3]) // 所有promise对象成功时才返回成功的promise,显然此时失败了
pAll.then(value => {
consloe.log('all onResolved()',value)
},
reason => {
console.log('all onRejected():',reason) // 打印 all onRejected(): 3
})
const pAll = Promise.all([p1, p2]) // 所有promise对象成功时才返回成功的promise,显然此时成功了
pAll.then(values => {
console.log('all onResolved()', values) // 打印成功的数组 all onResolved() (2) [1, 2] 结果数组顺序严格按照参数顺序
},
reason => {
console.log('all onRejected():', reason)
})
promise.race
const pRace = Promise.race([p1, p2, p3]) // 返回第一个promise的结果状态 看谁先完成
pRace.then(value => {
consloe.log('race onResolved()', value)
},
reason => {
console.log('race onRejected():', reason) // 打印 1
})
5. promise 的几个关键问题
- 如何改变promise的状态
- resolve(value):如果当前是pending就会变为resolved
- reject(reason):如果当前是pending就会变为rejected
- 抛出异常:如果当前时pending就会变为rejected
const p = new Promise((resolve, reject) => {
// resolve(1) // promise 变为resolved状态
// reject(2) // promise 变为rejected 状态
// throw new Error('出错了') // 抛出异常 promise 变为 rejected 状态
throw 3 // 可抛出任何数据
})
p.then(value => {
},
reason => {
console.log('reason', reason) // 打印 3 promise 变为rejected 状态
})
p.then(value => {
},
reason => {
console.log('reason2',reason) // 打印 3 promise 变为rejected 状态
}) // 两次失败回调都执行 成功也一样
-
一个promise指定多个成功/失败回调函数,都会调用吗?
- 当promise改变为对应状态时都会调用
-
改变promise 状态和指定回调函数谁先谁后?
- 都有可能,正常情况下是先指定回调函数再改变状态,但也可以先改状态再指定回调函数
这段代码的执行结果
new Promise((resolve, reject) => { resolve(1) }).then(value => { console.log('onResolved():', value) }, reason => { console.log('onRejected():', reason) }).then(value => { console.log('onResolved():', value) }, reason => { console.log('onRejected():', reason) })// 先打印 1 再打印 undefined 因为第一个.then产生的promise并没有得到数据
先指定回调函数,再改变状态
new Promise((resolve, reject) => { setTimeout(() => { resolve(1) // 后改变的状态 (同时指定数据),异步执行回调函数 }, 1000) }).then( // 先指定回调函数 value => { }, reason => { console.log('reason') } )
先改变状态,再执行回调
new Promise((resolve, reject) => { resolve(1) // 先改变状态(同时指定数据) }).then( // 后指定回调函数,异步执行回调函数 value => { console.log('value2',value) }, reason => { console.log('reason',reason) } ) // 或者 const p = new Promise((resolve, reject) => { setTimeout(() => { resolve(1) // 后改变的状态 }, 1000) }) setTimeout(() => { p.then( // 先指定回调函数 value => { }, reason => { console.log('reason') } ) }, 2000)
promise.then()返回的新promise的结果状态由什么决定呢?
答 : 简单表达 : 由then()指定的回调函数的返回执行结果决定
详细表达 :
- 如果抛出异常,新promise变为rejected,reason为抛出的异常
- 如果返回的是非promise的任意值,新promise变为resolved,value为返回的值
- 如果返回的是另一个新promise,此promise的结果就会成为新promise的结果
new Promise((resolve, reject) => { resolve(1) }).then(value => { console.log('onResolved():', value) // return 2 // return Promise.resolve(3) // return Promise.resolve(4) throw 5 }, reason => { console.log('onRejected():', reason) }).then(value => { console.log('onResolved():', value) }, reason => { console.log('onRejected():', reason) })
如何先改变状态再指定回调?
- 在执行器中直接调用resolve/reject函数
- .then延迟执行
-
promsie 如何串联多个操作任务
- promise 的then()返回一个新的promise 对象,可以继续使用.then()的链式调用
- 通过then的链式调用串连多个同步/异步任务
new Promise((resolve, reject) => {
resolve(1)
}).then(value => {
console.log('任务1的结果:', value)
console.log('执行任务2(同步)')
return 2
}).then(
value => {
console.log('任务2的结果:', value)
return new Promise((resolve, reject) => {
// 启动异步任务3
setTimeout(() => {
console.log('执行异步任务')
resolve(3)
}, 1000)
})
}
).then(value => {
console.log('任务3的结果:', value)
})
// 打印结果
//执行异步任务1
//index.html?_ijt=nk2cs3hseqha5cn1mdsgo8pbij:151 任务1的结果: 1
//index.html?_ijt=nk2cs3hseqha5cn1mdsgo8pbij:152 执行任务2(同步)
//index.html?_ijt=nk2cs3hseqha5cn1mdsgo8pbij:156 任务2的结果: 2
//index.html?_ijt=nk2cs3hseqha5cn1mdsgo8pbij:161 执行异步任务
//index.html?_ijt=nk2cs3hseqha5cn1mdsgo8pbij:167 任务3的结果: 3
// .then回调函数中异步任务需要使用new Promsie 封装起来才能传递到下一个.then
失败的回调会逐级传递
new Promise((resolve, reject) => {
reject(1)
}).then(value => {
console.log('onResolved1', value)
return 2
// 这里相当于 reason => {throw reason}
}).then(value => {
console.log('onResolved2()', value)
// 这里相当于 reason => {throw reason}
}).then(value => {
console.log('onResolved3()', value)
// 这里也相当于 reason => {throw reason}
}).catch(reason => {
console.log('onRejected1()', reason)
}) // onRejected1() 1
因此.then()返回的promise对象只有抛出异常或者返回一个失败的promsie才会失败
new Promise((resolve, reject) => {
reject(1)
}).then(value => {
console.log('onResolved1', value)
return 2
}).then(
value => {
console.log('onResolved2()', value)
}
).then(value => {
console.log('onResolved3()', value)
}).catch(reason => {
console.log('onRejected1()', reason)
}).catch(reason => {
return new Promise(() => { // 此时中断promise连
})
}).then(value => {
console.log('onResolved3()', value)
},
reason => {
console.log('onRejected2()', reason)
})
6. 自定义promise
码云地址:https://gitee.com/Coder-XO/myPromise_ES5function/blob/main/src/promise.js
代码里面有详细的注释