摘要
本文是promise详解的[上]
第一章绪论
本章包括实例对象与函数对象的概念;同步异步概念;报错的类型和信息等第二章promise的理解和使用
本章包括promise的基本流程;promise相比传统纯回调方式的优点;
promise的基本API使用;promise的几个关键问题(重难点!!!)
实例对象:new关键字产生的对象,称为实例对象,简称为对象
函数对象:函数是一种对象,将函数作为对象使用,称为函数对象
括号左边是函数
.左边是对象
函数也是一种对象
function Fn() { // Fn函数 } const fn = new Fn() // Fn是构造函数 fn是实例对象(简称为对象) console.log(Fn.prototype) // Fn是函数对象 Fn.call({}) // Fn是函数对象 $('#test') // jQuery函数 $.get('/test') // jQuery函数对象
自定义的函数,自己没有调用,最终执行的就是回调函数
立即执行,完全执行完了才结束,不会放到回调队列中
// 1. 同步回调函数 // 按顺序从上到下执行 // const arr = [1, 3, 5] arr.forEach(item => { // 遍历回调, 同步回调函数, 不会放入列队, 一上来就要执行完 console.log(item) }) console.log('forEach()之后')
不会立即执行 会放到回调队列中等待执行
// 2. 异步回调函数 setTimeout(() => { // 异步回调函数, 会放入队列中等待执行 console.log('timout callback()') }, 0) console.log('setTimeout()之后')
Error 所有错误的父类型
ReferenceError 引用的变量不存在
TypeError 数据类型不正确的错误
RangeError 数据值不在允许的范围之内
SyntaxError 语法错误
错误不处理下面的代码不执行
// ReferenceError: 引用的变量不存在 // console.log(a) // ReferenceError: a is not defined // TypeError: 数据类型不正确的错误 // let b // // console.log(b.xxx) // TypeError: Cannot read property 'xxx' of undefined // b = {} // b.xxx() // TypeError: b.xxx is not a function // RangeError: 数据值不在其所允许的范围内 // function fn() { // fn() // } // fn() // RangeError: Maximum call stack size exceeded // 超过能调用的次数限制 // SyntaxError: 语法错误 // const c = """" // SyntaxError: Unexpected string
捕获错误
try … catch
try{ let a; console.log(a.xxx); } catch(error){ console.log(error); } // 这里的error是对象
抛出错误
throw error
// 抛出错误: throw error function something() { if (Date.now()%2===1) { console.log('当前时间为奇数, 可以执行任务') } else { // 如果时间是偶数抛出异常, 由调用来处理 throw new Error('当前时间为偶数无法执行任务') } }
message 错误信息
stack属性 函数调用栈记录信息
是js中进行异步编程的新的解决方案(旧的是纯回调函数)
1、从语法上看promise是一个构造函数
2、从功能上说promise对象是用来封装一个异步操作并获取结果
pending变为resolved
pending变为rejected
只有这两种,且一个promise对象只能改变一次
无论成功 还是失败,都会有一个结果数据
成功的结果数据一般称为value
失败的结果数据一般称为reason
1、new Promise()
传一个函数作为参数,函数中启动异步任务
pending状态
2、执行异步操作
成功执行resolve() promise对象变为resolved状态
失败执行reject() promise对象变为rejected状态
3、.then
回调onResolve()
.then/catch回调onRejected()
4、返回一个新的promise对象
// 1、创建新的promise const p = new Promise((resolve, reject) => {//执行器函数 // 2、执行异步函数 setTimeout(() => { const time = Date.now()// 如果当前时间是偶数代表成功,否则失败 // 3.1成功 调用resolve(value) if (time % 2 === 0) { resolve('成功的,value=' + time) } else { // 3.2失败 调用reject(reason) reject('失败的,reason='+ time) } }, 1000) }) p.then( value => { // 接收得到的成功的value数据 onResolved console.log('成功的回调',value); }, reason => { // 接收得到的失败的reason数据 onRejected console.log('失败的回调',reason); } )
纯回调形式的异步操作必须先指定回调函数再执行异步任务
promise执行器函数是同步回调,先执行异步任务,再指定回调函数
1、相对于纯回调函数指定回调函数的形式更加的灵活
灵活:
启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以在异步任务得到结果之后再指定回调函数)
2、支持链式调用,解决回调地狱
什么是回调地狱?回调函数嵌套调用,涉及到多个异步操作,前后耦合性大,异常处理麻烦
回调地狱的最终解决方案async await
/* 1. 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的结果状态就是最终的结果状态 */
语法糖 4. Promise.resolve方法: (value) => {} value: 成功的数据或promise对象 说明: 返回一个成功/失败的promise对象 const p1 = new Promise((resolve,reject) => { resolve(1) }) // 等价于 const p1 = Promise.resolve(1)
如何改变promise的状态?
(1)resolve(value): 如果当前是pendding就会变resolved
(2)reject(reason): 如果当前是pendding就会变rejected
(3)抛出异常: 如果当前是pendding就会变为rejected
const p = new Promise((resolve, reject)=> { setTimeout(() => { // resolve('成功') // reject('失败的数据') throw 404 // 抛出错误也会变为rejected状态 // reason就是抛出的错误 }, 2000) }) p.then( reason => { console.log(reason); } )
一个promise指定多个成功/失败的回调函数都会调用吗?
当pending状态改变为对应状态时都会调用
```js
const p = new Promise((resolve, reject)=> {
setTimeout(() => {
// resolve(‘成功’)
// reject(‘失败的数据’)
throw 404
// 抛出错误也会变为rejected状态
// reason就是抛出的错误
}, 2000)
})
p.then(
reason => {
console.log(reason);
}
)
p.then(
reason => {
console.log(reason);
}
)
改变promise状态和指定回调函数谁先谁后?
(1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2)如何先改状态再指定回调?
①在执行器中直接调用resolve()/reject() (同步执行)
②延迟更长时间才调用then() (加定时器函数)
(3)什么时候才能得到数据?
①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
promise的执行器函数里面的函数(resolve()/reject())是同步执行的,
.then本身是同步执行的,但是里面的成功/失败的处理回调函数都是异步
执行的
const p = new Promise((resolve, reject) => { console.log(11); resolve(1) console.log(22); reject(2) }) p.then( // then本身是同步执行的 // then里面的回调函数是异步的 value => { console.log(value); }, reason => { console.log(reason); } ) console.log(0); // 11 22 0 1
.then()会返回一个新的promise对象
promise.then()返回的新promise的结果状态由什么决定?
(1)简单表达: 由then()指定的回调函数执行的结果决定
(2)详细表达:
①如果抛出异常, 新promise变为rejected, reason为抛出的异常
②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值(例如返回数字)
③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
new Promise((resolve, reject) => { resolve(1) reject(2) }).then( value => {// 此回调函数执行成功了 无返回值 默认返回undefined console.log('onResolved1()', value) }, reason => { console.log('onRejected1()', reason) } ).then( value => {// 此回调函数根据上一个.then()返回的promise对象状态决定 执行成功 但是返回了一个undefined console.log('onResolved2()', value) }, reason => { console.log('onRejected2()', reason) } ) // 1 undefined
new Promise((resolve, reject) => { // resolve(1) reject(2) }).then( value => { console.log('onResolved1()', value) }, reason => { console.log('onRejected1()', reason) return 66 } ).then( value => { console.log('onResolved2()', value) }, reason => { console.log('onRejected2()', reason) } ) // onRejected 2 onResolved 66
promise如何串连多个操作任务?
(1)promise的then()返回一个新的promise
, 可以开成then()的链式调用
(2)通过then的链式调用串连多个同步/异步任务
promise异常传/穿透?
(1)当使用promise的then链式调用时, 可以在最后指定失败的回调,(.catch())
(2)前面任何操作出了异常, 都会传到最后失败的回调中处理
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('onRejected',reason); } )
当前面的执行出现错误,不是从第一个promise一下子到最后的catch()中
会发生异常穿透
等价于:
new Promise((resolve, reject) => { // resolve(1) reject(1) }).then( value => { console.log('onResolved1()', value) return 2 }, reason => { throw reason } ).then( value => { console.log('onResolved2()', value) return 3 }, reason => { throw reason } ).then( value => { console.log('onResolved3()', value) }, reason => { throw reason } ).catch( reason => { console.log('onRejected', reason); } )
注意,除了throw reason
抛出异常
也等价于 reason => Promise.reject(reason)
箭头函数单条语句不加return,则默认返回单条语句
所以throw reason
需要{}
,而reason => Promise.reject(reason)
不需要
就是返回一个promise作为这一级.then()的返回对象
return new Promise(() => {})