Promise对象 异步编程
Promise 的含义
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise
对象有以下两个特点。
(1)对象的状态不受外界影响。Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise
这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise
对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
Promise
也有一些缺点:
- 无法取消
Promise
,一旦新建它就会立即执行,无法中途取消。 - 如果不设置回调函数,
Promise
内部抛出的错误,不会反应到外部。 - 当处于
pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
为什么要用promise
1. 指定回调函数的方式更加灵活:
旧的: 必须在启动异步任务前指定
promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
const p = new Promise((resolve, reject) => { console.log('执行 executor同步函数') let time = Date.now(); setTimeout(() => { if (time % 2 === 0) { resolve(time) } else { reject(time) } }, 1000) }) setTimeout(() => { p.then(value => { console.log('value', value) }, reason => { console.log('reason', reason) }) }, 3000)
2. 支持链式调用, 可以解决回调地狱问题 什么是回调地狱: 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调函数执行的条件 回调地狱的缺点: 不便于阅读 / 不便于异常处理 解决方案:promise链式调用 终极解决方案:async/await
Promise API
1. Promise构造函数: Promise (excutor) {} excutor 执行器函数: 同步执行 (resolve, reject) => {} resolve函数: 内部定义成功时我们调用的函数 value => {} reject函数: 内部定义失败时我们调用的函数 reason => {} 说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行 定义:new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>; 2. Promise.prototype.then方法: (onResolved, onRejected) => {} onResolved函数: 成功的回调函数 (value) => {} onRejected函数: 失败的回调函数 (reason) => {} 说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调 返回一个新的promise对象 then接口定义:then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>; 3. Promise.prototype.catch方法: (onRejected) => {} onRejected函数: 失败的回调函数 (reason) => {} 说明: then()的语法糖, 相当于: then(undefined, onRejected) catch接口定义:catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>; 4. Promise.resolve方法: (value) => {} value: 成功的数据或promise对象 说明: 返回一个成功/失败的promise对象 resolve<T>(value: T | PromiseLike<T>): Promise<T>; 5. Promise.reject方法: (reason) => {} reason: 失败的原因 说明: 返回一个失败的promise对象 reject<T = never>(reason?: any): Promise<T>; 6. Promise.all方法: (promises) => {} promises: 包含n个promise的数组 说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败 all<T>(values: readonly (T | PromiseLike<T>)[]): Promise<T[]>; 7. Promise.race方法: (promises) => {} promises: 包含n个promise的数组 说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态 race<T>(values: readonly T[]): Promise<T extends PromiseLike<infer U> ? U : T>;
使用的常见问题
- 如何改变promise的状态?
- resolve(value): 如果当前是pending就会变为resolved
-
reject(reason): 如果当前是pending就会变为rejected
-
抛出异常: 如果当前是pending就会变为rejected
- 一个promise指定多个成功/失败回调函数, 都会调用吗?
- 当promise改变为对应状态时都会调用
-
改变promise状态和指定回调函数谁先谁后?(1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调(2)如何先改状态再指定回调?①在执行器中直接调用resolve()/reject()②延迟更长时间才调用then()(3)什么时候才能得到数据?①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
-
promise.then()返回的新promise的结果状态由什么决定?(1)简单表达: 由then()指定的回调函数执行的结果决定(2)详细表达:①如果抛出异常, 新promise变为rejected, reason为抛出的异常②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
-
promise如何串连多个操作任务?(1)promise的then()返回一个新的promise, 可以开成then()的链式调用(2)通过then的链式调用串连多个同步/异步任务
-
promise异常传透?(1)当使用promise的then链式调用时, 可以在最后指定失败的回调,(2)前面任何操作出了异常, 都会传到最后失败的回调中处理
-
中断promise链?(1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数(2)办法: 在回调函数中返回一个pending状态的promise对象 return new Promise(()=>{})
// 自定义Promise // ES5匿名函数自调用实现模块化 (function (window) { const PENDING = 'pending' const RESOLVED = 'resolved' const REJECTED = 'rejected' // 参数为executor函数 function Promise(executor) { const that = this // 三个属性 that.status = PENDING //Promise对象状态属性,初始状态为 pending that.data = 'undefined' // 用于存储结果数据 that.callbacks = [] //保存待执行的回调函数 ,数据结构:{onResolved(){},onRejected(){}} function resolve(value) { // RESOLVED 状态只能改变一次 if (that.status !== PENDING) { return } that.status = RESOLVED that.data = value //执行异步回调函数 onResolved if (that.callbacks.length > 0) { setTimeout(() => { // 放入队列中执行所有成功的回调 that.callbacks.forEach(callbackObj => { callbackObj.onResolved(value) }) }) } } function reject(seaon) { if (that.status !== PENDING) { return } that.status = REJECTED that.data = seaon //执行异步回调函数 onRejected if (that.callbacks.length > 0) { setTimeout(() => { // 放入队列中执行所有失败的回调 that.callbacks.forEach(callbackObj => { callbackObj.onRejected(seaon) }) }) } } try { //执行器函数立即执行 executor(resolve, reject) } catch (e) { reject(e) } } //Promise原型对象 then ,两个回掉函数 成功 onResolved ,失败onRejected //返回一个新的Promise对象 Promise.prototype.then = function (onResolved, onRejected) { onResolved = typeof onResolved === 'function' ? onResolved : value => value // 向后传递成功的value // 指定默认的失败的回调(实现错误/异常传透的关键点) onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } // 抽后传递失败的reason const that = this return new Promise((resolve, reject) => { //调用指定回调函数处理, 根据执行结果, 改变return的promise的状态 function handle(callback) { // 调用成功的回调函数 onResolved //1.如果抛出异常,return的promise就 会失败,reason就 是error //2.如果回调函数返回不是promise, return的promise就 会成功,value就是返回的值 //3.如果回调函数返回是promise, return的promise结 果就是这个promise的结果 try { const result = callback(that.data); if (result instanceof Promise) { result.then(value => resolve(value), reason => reject(reason)) } else { resolve(result) } } catch (e) { reject(e) } } // 当前状态还是pending状态, 将回调函数保存起来 if (that.status === PENDING) { that.callbacks.push({ onResolved(value) { handle(onResolved) }, onRejected(reason) { handle(onRejected) } }) } else if (that.status === RESOLVED) { setTimeout(() => { handle(onResolved) }) } else { setTimeout(() => { //调用失败的回调函数 onRejected handle(onRejected) }) } }) } //Promise原型对象 catch ,参数为失败的回掉函数 onRejected //返回一个新的Promise对象 Promise.prototype.catch = function (onRejected) { return this.then(undefined, onRejected) } // Promise函数对象的 resolve 方法 //返回一个新的Promise对象,Promise.resolve()中可以传入Promise Promise.resolve = function (value) { return new Promise((resolve, reject) => { if (value instanceof Promise) { value.then(resolve, reject) } else { resolve(value) } }) } // Promise函数对象的 reject 方法 //返回一个新的Promise对象 Promise.reject中不能再传入Promise Promise.reject = function (reason) { return new Promise((resolve, reject) => { reject(reason) }) } // Promise函数对象的 all 方法,接受一个promise类型的数组 // 返回一个新的Promise对象 Promise.all = function (promises) { // 保证返回的值得结果的顺序和传进来的时候一致 // 只有全部都成功长才返回成功 const values = new Array(promises.length) // 指定数组的初始长度 let successCount = 0 return new Promise((resolve, reject) => { promises.forEach((p, index) => { // 由于p有可能不是一个Promise Promise.resolve(p).then( value => { successCount++ values[index] = value if (successCount === promises.length) { resolve(values) } }, // 如果失败 reason => { reject(reason) }) }) }) } // Promise函数对象的 race 方法,接受一个promise类型的数组 // 返回一个新的Promise对象 Promise.race = function (promises) { return new Promise((resolve, reject) => { promises.forEach(p => { Promise.resolve(p).then( value => { resolve(value) }, reason => { reject(reason) }) }) }) } // 把Promise暴露出去 window.Promise = Promise })(window)
使用Class定义
// 自定义Promise // ES5匿名函数自调用实现模块化 (function (window) { const PENDING = 'pending' const RESOLVED = 'resolved' const REJECTED = 'rejected' class Promise { // 参数为executor函数 constructor(executor) { const that = this // 三个属性 that.status = PENDING //Promise对象状态属性,初始状态为 pending that.data = 'undefined' // 用于存储结果数据 that.callbacks = [] //保存待执行的回调函数 ,数据结构:{onResolved(){},onRejected(){}} function resolve(value) { // RESOLVED 状态只能改变一次 if (that.status !== PENDING) { return } that.status = RESOLVED that.data = value //执行异步回调函数 onResolved if (that.callbacks.length > 0) { setTimeout(() => { // 放入队列中执行所有成功的回调 that.callbacks.forEach(callbackObj => { callbackObj.onResolved(value) }) }) } } function reject(seaon) { if (that.status !== PENDING) { return } that.status = REJECTED that.data = seaon //执行异步回调函数 onRejected if (that.callbacks.length > 0) { setTimeout(() => { // 放入队列中执行所有失败的回调 that.callbacks.forEach(callbackObj => { callbackObj.onRejected(seaon) }) }) } } try { //执行器函数立即执行 executor(resolve, reject) } catch (e) { reject(e) } } //Promise原型对象 then ,两个回掉函数 成功 onResolved ,失败onRejected //返回一个新的Promise对象 then(onResolved, onRejected) { onResolved = typeof onResolved === 'function' ? onResolved : value => value // 向后传递成功的value // 指定默认的失败的回调(实现错误/异常传透的关键点) onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } // 抽后传递失败的reason const that = this return new Promise((resolve, reject) => { //调用指定回调函数处理, 根据执行结果, 改变return的promise的状态 function handle(callback) { // 调用成功的回调函数 onResolved //1.如果抛出异常,return的promise就 会失败,reason就 是error //2.如果回调函数返回不是promise, return的promise就 会成功,value就是返回的值 //3.如果回调函数返回是promise, return的promise结 果就是这个promise的结果 try { const result = callback(that.data); if (result instanceof Promise) { result.then(value => resolve(value), reason => reject(reason)) } else { resolve(result) } } catch (e) { reject(e) } } // 当前状态还是pending状态, 将回调函数保存起来 if (that.status === PENDING) { that.callbacks.push({ onResolved(value) { handle(onResolved) }, onRejected(reason) { handle(onRejected) } }) } else if (that.status === RESOLVED) { setTimeout(() => { handle(onResolved) }) } else { setTimeout(() => { //调用失败的回调函数 onRejected handle(onRejected) }) } }) } //Promise原型对象 catch ,参数为失败的回掉函数 onRejected //返回一个新的Promise对象 catch(onRejected) { return this.then(undefined, onRejected) } // Promise函数对象的 resolve 方法 //返回一个新的Promise对象,Promise.resolve()中可以传入Promise static resolve = function (value) { return new Promise((resolve, reject) => { if (value instanceof Promise) { value.then(resolve, reject) } else { resolve(value) } }) } // Promise函数对象的 reject 方法 //返回一个新的Promise对象 Promise.reject中不能再传入Promise static reject = function (reason) { return new Promise((resolve, reject) => { reject(reason) }) } // Promise函数对象的 all 方法,接受一个promise类型的数组 // 返回一个新的Promise对象 static all = function (promises) { // 保证返回的值得结果的顺序和传进来的时候一致 // 只有全部都成功长才返回成功 const values = new Array(promises.length) // 指定数组的初始长度 let successCount = 0 return new Promise((resolve, reject) => { promises.forEach((p, index) => { // 由于p有可能不是一个Promise Promise.resolve(p).then( value => { successCount++ values[index] = value if (successCount === promises.length) { resolve(values) } }, // 如果失败 reason => { reject(reason) }) }) }) } // Promise函数对象的 race 方法,接受一个promise类型的数组 // 返回一个新的Promise对象 static race = function (promises) { return new Promise((resolve, reject) => { promises.forEach(p => { Promise.resolve(p).then( value => { resolve(value) }, reason => { reject(reason) }) }) }) } } // 把Promise暴露出去 window.Promise = Promise })(window)
来自:https://www.bilibili.com/video/BV1MJ41197Eu?from=search&seid=1177747046204864464