整理 Promise 以及前端一些常用知识。
实例对象与函数对象的区别
- 实例对象:new函数产生的对象
- 函数对象:将函数作为对象使用时,称为函数对象。()左边是函数,.左边是函数对象
回调函数
回调函数特点:你声明的,没有调用,最终执行了。
- 同步回调:立即执行,完全执行完了才结束
- 异步回调:不会立即执行,会放入回调队列中将来执行 (定时器/ajax/promise)
JS 常见错误
- ReferenceError: 引用变量不存在
- TypeError: 数据类型不正确
- RangeError: 数据值不在允许的范围内
- SyntaxError: 语法错误
错误处理
- 捕获错误: try ... catch, 在Promise执行器中用 try... catch,Promise外用Catch方法。因为try... catch 只能用于同步代码捕获。
try {
...
} catch(error) {
...
}
error包括 stack和message两个属性
- 抛出错误: throw error
Promise
- Promise是JS中进行异步编程的新的解决方案。
具体而言,从语法上说Promise是一个构造函数,从功能上来说Promise对象用于封装一个异步的操作并可以获取其结果。
Promise状态
1. pending变为resolved
2. pending变成rejected
一个Promise对象只能改变一次,成功的结果数据一般称为value,失败的结果数据一般称为reason。
-
Promise流程
-
new Promise() 此时Promise处于pendding状态
-
执行异步操作,成功了执行resolve(),失败了执行reject()
-
resolve() --> pendding变为resolved,rejected() --> pendding变为rejected
-
resolved 执行通过.then()指定的回调 onResolved() 生成新的Promise对象,rejected 执行通过.then()/.catch()指定回调 onRejected() 通过.then()可以生成新的Promise对象。
-
-
为什么用Promise
-
指定回调函数的方式更加灵活。以前异步操作的回调函数必须在启动异步任务前指定。Promise的回调函数甚至可以在异步结束后指定。
-
支持链式调用,可以解决回调地狱
回调地狱:回调函数嵌套调用,完成1后完成2....
Promise解决回调地狱:链式的.then
<script>
dosomething().then(funciton(result){ //dosomething: Promise对象
return dosomethingElse(result)
})
.then(funciton(newResult){
return dosomeThirdThing(newResult)
})
.then(funciton(findResult){
console.log('Got final result')
})
.catch(failureCallback)
</script>
async/awit:回调地狱的终极解决方案
async function request() {
try {
const result = await doSomething()
const newResult = await doSomethingElse(result)
const finalResult = await doThirdThing(newResult)
console.log('Got final result')
} catch (error) {
failureCallback(error)
}
}
- Promise基本使用
<script>
const p = new Promise((resolve, reject) => {
// 执行函数 成功了条用resolve(value) 失败了调用 reject(value)
setTimeout(()=>{
const time = Date.now()
if (time %2 ==0) {
resolve("成功,time=" + time)
} else {
reject("失败,time=" + time)
}
},1000)
})
p.then(
value => { console.log('成功的回调',value)},
reason => { console.log('失败的回调',reason)
}
)
</script>
-
Promise API
-
Promise构造函数:Promise(executor) {}
- executor: 同步执行 (resolve,reject) => {}
- resolve: 内部定义成功时我们调用的函数 value => {}
- reject: 内部定义失败时我们调用的函数 reason => {}
executor时同步执行,executor内代码是异步执行的
-
Promise.prototype.then: (onResolved, onRejected) => {}
- onResolved: 成功的回调 (value) => {}
- onRejected: 失败的回调 (reason) => {} 返回一个新的Promise对象
-
Promise.prototype.catch: (onRejected) => {}
- onRejected: 失败的回调 (reason) => {}
相当于 then(undefined, onRejected)
-
Promise.resolve: (value) => {}
value: 成功的数据或者Promise对象
-
Promise.reject: (reason) => {}
reason: 失败的原因
-
Promise.all: (Promises) => {}
Promises: 包含n个promise数组,返回一个新的Promise,只有所有的Promise都成功才成功,否则返回第一个的失败
-
Promise.race: (Promises) => {}
Promises: 包含n个promise数组,返回一个新的Promise,返回第一个完成的Promise结果
-
-
Promise的几个问题
-
Promise状态改变:1) resolve(value): pendding -> resolved 2) reject(reason): pendding -> rejected 3) 抛出异常: pendding-> rejected
-
Promise状态改变时,会调用所有指定的成功/失败的回调函数。
-
指定回调函数和改变状态的顺序,都有可能。默认改变状态和.then()是同步执行,若设置定时则改为异步。
-
Promise.then()返回新的Promise结果(resolve/reject)由.then()指定的回调函数 返回值决定。如果抛出异常,则新的Promise变为rejected;如果返回非Promise任意值,变为resolved,value为返回值;如果返回值是另一个新的Promise,Promise结果就是新的Promise结果。
-
Promise 串联多个操作任务: 1) .then()链式调用 2) 同步就直接return,异步声明新的Promise对象。
-
Promise 异常穿透,链式调用时可以在最后指定失败的回调,通过逐层传递给最后指定的失败回调。
-
中断 Promise 链,返回一个pending的Promise。
return new Promise(()=>{}) //返回一个pending的Promise -
-
Promise、async/await、Generator
- 在函数名前加async,在函数体内使用await。async 是基于Promise的封装,使得链式调用更简单,代码更简洁。
//promise const makeRequest = () => { return promise1() .then(value1 => { // do something return promise2(value1) .then(value2 => { // do something return promise3(value1, value2) }) }) } // async const makeRequest = async () => { const val1 = await promise1() const val2 = await promise2(val1) return promise3(val1,val2) }-
Generator 函数是将函数分步骤阻塞,只有主动调用 next() 才能进行下一步。 通过function* (){} 声明。async 是Generator的语法糖。 解决以下问题:1) async函数自带执行器,2) async表示函数里有异步操作,await表示紧跟再后面的表达式需要等待结果, 3)yield命令后,只能是Thunk函数或Promise对象,而async函数的await命令后面,可以是Promise对象和原始类型的值,4)返回值是Promise对象,可以使用then方法指定下一步操作。
-
宏队列/微队列
-
JS中存储执行回调函数包括2个队列:宏队列和微队列。
-
宏队列:用来保存执行的宏任务:定时器回调/DOM事件回调/ajax回调。
-
微队列:用来保存执行的微任务:Promise回调/MutationObserver回调。
-
JS引擎首先执行所有初始化同步任务代码。每次准备取出一个宏任务执行前,都要将所有微任务一个个取出来执行。
-
-
手写(自定义)Promise
(function (window) { const PENDING = 'pending' const RESOLVED = 'resolved' const REJECTED = 'rejected' function Promise(executor) { // Promise对象属性 const _this = this _this.status = PENDING _this.data = undefined // 存储回调函数 {onResolved, onRejected} _this.callbacks = [] // 1. resolve/reject 只有当status是pendding时才能嗲用 // 2. 只有throw /reject() 才会调用reject() // 3. this问题, 直接调用 resolve()/reject() this为windows,需要保存this // 4. 回调函数声明和状态改变无法确定先后,需要在函数内判断 function resolve(value) { // 如果状态不是pendding, 不能修改 if (_this.status !== PENDING) return _this.status = RESOLVED _this.data = value // 判断是否存在回调 if (_this.callbacks.length > 0) { // 异步执行回调 setTimeout(() => { _this.callbacks.forEach(callbackObj => { callbackObj.onResolved(value) }) }); } } function reject(reason) { // 如果状态不是pendding, 不能修改 if (_this.status !== PENDING) return _this.status = REJECTED _this.data = reason // 判断是否存在回调 if (_this.callbacks.length > 0) { // 异步执行回调 setTimeout(() => { _this.callbacks.forEach(callbackObj => { callbackObj.onRejected(reason) }) }); } } try { executor(resolve, reject) } catch (error) { reject(error) } } // Promise 原型对象 .then() 指定成功/失败回调,返回新的Promise对象 Promise.prototype.then = function (onResolved, onRejected) { onResolved = typeof onResolved === 'function' ? onResolved : value => value onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } const _this = this return new Promise((resolve, reject) => { function handle(callback) { try { // 获取新的Promise返回值 const result = callback(_this.data) // 新的Promise返回值若为Promise对象,结果是该对象的返回值 if (result instanceof Promise) { result.then( value => resolve(value), reason => reject(reason) ) } else { // 新的Promise返回值不是Promise对象,结果是该执行resolve回调 resolve(result) } } catch (error) { // 新的Promise返回值throw,结果是该执行reject回调 reject(error) } } if (_this.status === PENDING) { _this.callbacks.push({ onResolved() { handle(onResolved) }, onRejected() { handle(onRejected) } }) } else if (_this.status === RESOLVED) { setTimeout(() => { handle(onResolved) }); } else { setTimeout(() => { handle(onRejected) }); } }) } // Promise 原型对象 .catch() 指定失败回调,返回新的Promise对象 Promise.prototype.catch = function (onRejected) { return this.then(undefined, onRejected) } // Promise函数对象 resolve 返回结果为value的成功Promise Promise.resolve = function (value) { return new Promise((resolve, reject) => { // 如果value不是Promise对象,执行resolve if (value instanceof Promise) { value.then(resolve, reject) } else { resolve(value) } }) } // Promise函数对象 reject 返回结果为value的失败Promise Promise.reject = function (reason) { // 返回失败的promise return new Promise((resolve, reject) => { reject(reason) }) } // Promise函数对象 all 返回一个Promise,所有成功时才成功,否则返回第一个失败的 Promise.all = function (promises) { const values = new Array(promises.length) let count = 0 return new Promise((resolve, reject) => { promises.forEach((p, index) => { Promise.resolve(p).then( value => { count++ values[index] = value if (count === promises.length) { resolve(values) } }, reason => { reject(reason) } ) }) }) } // Promise函数对象 race 返回第一个成功的Promise Promise.race = function (promises) { return new Promise((resolve, reject) => { promises.forEach((p, index) => { Promise.resolve(p).then( value => {resolve(value)}, reason => {reject(reason)} ) }) }) } window.Promise = Promise })(window)