回调嵌套,回调地狱
错误捕获不好处理
多个异步同步问题 Promise.all
Promise是一个类,默认浏览器高版本或node都是自带Promise的
如果低版本没有自带,我们可以使用es6-promise插件
3.1 三个状态
Pending等待态
fulfilled成功态
rejected失败态
只有等待态才能变成成功态/失败态
如果状态变化,不能在修改状态
const PENDING = 'Pending' const SUCCESS = 'fulfilled' const FAIL = 'rejected' class Promise { constructor(executor){ //初始化状态值为等待态 this.status=PENDDING //在调用resolve或者reject时可能回传值 this.value=undefined this.fail=undefined //成功态回调 let resolve=(value)=>{ //只有等待态才能修改状态值 if(this.status===PENDDING){ this.status = SUCCESS this.value=value } } //失败态回调 const reject=(fail)=>{ //只有等待态才能修改状态值 if(this.status===PENDDING){ this.status= FAIL this.fail=fail } } executor(resolve,reject) } then(fulfilled,rejected){ //从等待态自己resolve方法 if(this.status===SUCCESS){ fulfilled(this.value) } //从等待态自己reject方法 if(this.status===FAIL){ rejected(this.fail) } } } module.exports=Promise
每个Promise的实例上都有then方法
Promise有多个状态如果成功会让成功的函数依次执行
如果失败会让失败的函数依次执行
异步Promise,使用发布订阅模式
在等待态中,将所有的成功或者失败的回调都订阅存储到数组中,当状态从等待态变为成功态或者失败态时,遍历所有订阅的成功回调执行或者失败回调执行
const PENDING = 'Pending' const SUCCESS = 'fulfilled' const FAIL = 'rejected' class Promise { constructor(executor){ //初始化状态值为等待态 this.status=PENDING //在调用resolve或者reject时可能回传值 this.value=undefined this.fail=undefined //用来存储所有的成功,失败态 this.onResolveCallback=[] this.onRejectCallbakc=[] //成功态回调 let resolve=(value)=>{ //只有等待态才能修改状态值 if(this.status===PENDING){ this.status = SUCCESS this.value=value //发布所有订阅的消息 this.onResolveCallback.forEach(fn=>fn()) } } //失败态回调 const reject=(fail)=>{ //只有等待态才能修改状态值 if(this.status===PENDING){ this.status= FAIL this.fail=fail //发布所有订阅的消息 this.onRejectCallbakc.forEach(fn=>fn()) } } executor(resolve,reject) } then(fulfilled,rejected){ //从等待态自己resolve方法 if(this.status===SUCCESS){ fulfilled(this.value) } //从等待态自己reject方法 if(this.status===FAIL){ rejected(this.fail) } if(this.status===PENDDING){ console.log('pedding'); //订阅所有的成功,失败态 this.onResolveCallback.push(()=>fulfilled(this.value)) this.onRejectCallbakc.push(()=>rejected(this.fail)) } } } module.exports=Promise
Promise的链式调用,其实质就是每次then返回一个新的Promise实例
const PENDING = 'Pending' const SUCCESS = 'fulfilled' const FAIL = 'rejected' function resolvePromise(x, promise2, resolve, reject) { //如果x与promise相等就会出现自己调用自己 if (x === promise2) { return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>')) } //为了防止别人写的promise同时调用成功和失败的方法 let called //判断x是不是一个对象或者方法 if (typeof x === 'function' || (typeof x === 'object' && x != null)) { //判断x是不是一个promise try { let then = x.then if (typeof then === 'function') { then.call(x, y => { if (called) return called = true resolvePromise(y, promise2, resolve, reject) }, error => { if (called) return called = true reject(error) }) } else { resolve(x) } } catch (error) { if (called) return called = true reject(error) } } else { resolve(x) } } class Promise { constructor(executor) { //初始化状态值为等待态 this.status = PENDING //在调用resolve或者reject时可能回传值 this.value = undefined this.fail = undefined //用来存储所有的成功,失败态 this.onResolveCallback = [] this.onRejectCallback = [] //成功态回调 let resolve = (value) => { //只有等待态才能修改状态值 if (this.status === PENDING) { this.status = SUCCESS this.value = value //发布所有订阅的消息 this.onResolveCallback.forEach(fn => fn()) } } //失败态回调 const reject = (fail) => { //只有等待态才能修改状态值 if (this.status === PENDING) { this.status = FAIL this.fail = fail //发布所有订阅的消息 this.onRejectCallback.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (e) { reject(e) } } then(onFulfilled, onRejected) { //为了实现值得穿透 //p.then().then().then(val => console.log(val)) onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err } //为了解决链式调用问题,每一次then后,返回值需要是一个Promise let promise2 = new Promise((resolve, reject) => { //从等待态自己resolve方法 if (this.status === SUCCESS) { //为了是传入的promise2不为null setTimeout(() => { try { //如果返回的x仍然是一个Promise我们需要处理 let x = onFulfilled(this.value) //处理x resolvePromise(x, promise2, resolve, reject) } catch (e) { reject(e) } }) } //从等待态自己reject方法 if (this.status === FAIL) { setTimeout(() => { try { let x = onRejected(this.fail) resolvePromise(x, promise2, resolve, reject) } catch (e) { reject(e) } }) } if (this.status === PENDING) { // console.log('PENDING'); //订阅所有的成功,失败态 this.onResolveCallback.push(() => { setTimeout(() => { try { let x = onFulfilled(this.value) resolvePromise(x, promise2, resolve, reject) } catch (e) { reject(e) } }) }) this.onRejectCallback.push(() => { setTimeout(() => { try { let x = onRejected(this.fail) resolvePromise(x, promise2, resolve, reject) } catch (e) { reject(e) } }) }) } }) return promise2 } } //测试写的库是否合格promises-aplus-tests Promise.defer = Promise.deferred = function () { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve dfd.reject = reject }) return dfd } module.exports = Promise
resolve中传递的是一个Promise实例,需要等待这个promise执行完成,在调用后续的then方法,因此需要在源码中判断resolve携带的参数是不是promise,如果是promise,需要执行传递的这个promise.then方法,进行递归调用,直到最后返回.then的最终结果
const p=new Promise((resolve,reject)=>{ resolve(new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(111) },2000) })) }) p.then(data=>console.log(data))
const p=new Promise((resolve,reject)=>{ resolve(new Promise((resolve,reject)=>{ resolve(new Promise((resolve,reject)=>{ resolve(new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(111) },2000) })) })) })) }) p.then(data=>console.log(data))
源码修改:
在constructor构造函数中,对resolve方法传递的value值进行判断
constructor(executor) { //初始化状态值为等待态 this.status = PENDING //在调用resolve或者reject时可能回传值 this.value = undefined this.fail = undefined //用来存储所有的成功,失败态 this.onResolveCallback = [] this.onRejectCallback = [] //成功态回调 let resolve = (value) => { //如果resolve里面传递的是一个promise if(value instanceof Promise){//判断value是 Promise的实例对象 return value.then(resolve,reject) } //只有等待态才能修改状态值 if (this.status === PENDING) { this.status = SUCCESS this.value = value //发布所有订阅的消息 this.onResolveCallback.forEach(fn => fn()) } } //失败态回调 const reject = (fail) => { //只有等待态才能修改状态值 if (this.status === PENDING) { this.status = FAIL this.fail = fail //发布所有订阅的消息 this.onRejectCallback.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (e) { reject(e) } }
catch方法是then的语法糖
catch(onRejected){ return this.then(null,onRejected) }
finally不管promise走的是resolve还是reject都会调用finally
Promise.resolve=function(callback){ return new Promise((resolve)=>{ resolve(callback) }) } Promise.reject=function(callback){ return new Promise((resolve,reject)=>{ reject(callback) }) } //finally里面要使用resolve是因为要等待callback()执行完成,在执行后续的then方法 Promise.prototype.finally=function(callback){ return this.then(data=>{ return Promise.resolve(callback()).then(()=>data) },err=>{//这里不能使用Promise.reject,因为如果使用了reject,那么就不会等待callback方法执行 return Promise.resolve(callback()).then(()=>err) }) }
异步同步 让所有的异步 并发执行 有序输出
const fs=require('fs').promises Promise.all([fs.readFile('./name.txt','utf8'),fs.readFile('./age.txt','utf8'),3,4]).then(data=>console.log(data))
Promise源码修改
多个异步并发,解决办法
计数器
//判断是否是Promise function isPromise(value){ if(typeof value ==='function' || (typeof value==='object' && value!=null)){ if(typeof value.then==='function'){ return true } } return false } Promise.all=function(values){ return new Promise((resolve,reject)=>{ let arr=[] //计数器,用于计数是否执行完成所有的任务 let num=0 //将返回的值以下标的形式存起来 processData =(key,value)=>{ arr[key]=value if(++num===values.length){ resolve(arr) } } for(let i=0;i<values.length;i++){ let current=values[i] if(isPromise(current)){ current.then(x=>{ processData (i,x) },reject) }else{ processData(i,current) } } }) }
第一个成功就成功,输入第一个结果,第一个失败就失败
Promise.race=function(values){ return new Promise((resolve,reject)=>{ for(let i=0;i<values.length;i++){ let current=values[i] if(isPromise(current)){ current.then(resolve,reject) }else{ resolve(current) } } }) }
面试题:中断Promise
//中断Promise let p = new Promise((resolve, reject) => { setTimeout(() => { resolve() }, 3000) }) function wrap(promise) { let about let newPromise = new Promise((resolve, reject) => { about = reject }) let p = Promise.race([newPromise, promise]) p.about = about return p } let p1 = wrap(p) setTimeout(() => { console.log('中断操作') p1.about('err') }, 2000) p1.then((value) => { console.log('没中断走这个') },err=>{ console.log(err) })
const PENDING = 'Pending' const SUCCESS = 'fulfilled' const FAIL = 'rejected' function resolvePromise(x, promise2, resolve, reject) { //如果x与promise相等就会出现自己调用自己 if (x === promise2) { return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>')) } //为了防止别人写的promise同时调用成功和失败的方法 let called //判断x是不是一个对象或者方法 if (typeof x === 'function' || (typeof x === 'object' && x != null)) { //判断x是不是一个promise try { let then = x.then if (typeof then === 'function') { then.call(x, y => { if (called) return called = true resolvePromise(y, promise2, resolve, reject) }, error => { if (called) return called = true reject(error) }) } else { resolve(x) } } catch (error) { if (called) return called = true reject(error) } } else { resolve(x) } } class Promise { constructor(executor) { //初始化状态值为等待态 this.status = PENDING //在调用resolve或者reject时可能回传值 this.value = undefined this.fail = undefined //用来存储所有的成功,失败态 this.onResolveCallback = [] this.onRejectCallback = [] //成功态回调 let resolve = (value) => { //如果resolve里面传递的是一个promise if(value instanceof Promise){//判断value是 Promise的实例对象 return value.then(resolve,reject) } //只有等待态才能修改状态值 if (this.status === PENDING) { this.status = SUCCESS this.value = value //发布所有订阅的消息 this.onResolveCallback.forEach(fn => fn()) } } //失败态回调 const reject = (fail) => { //只有等待态才能修改状态值 if (this.status === PENDING) { this.status = FAIL this.fail = fail //发布所有订阅的消息 this.onRejectCallback.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (e) { reject(e) } } catch(onRejected){ return this.then(null,onRejected) } then(onFulfilled, onRejected) { //为了实现值得穿透 //p.then().then().then(val => console.log(val)) onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err } //为了解决链式调用问题,每一次then后,返回值需要是一个Promise let promise2 = new Promise((resolve, reject) => { //从等待态自己resolve方法 if (this.status === SUCCESS) { //为了是传入的promise2不为null setTimeout(() => { try { //如果返回的x仍然是一个Promise我们需要处理 let x = onFulfilled(this.value) //处理x resolvePromise(x, promise2, resolve, reject) } catch (e) { reject(e) } }) } //从等待态自己reject方法 if (this.status === FAIL) { setTimeout(() => { try { let x = onRejected(this.fail) resolvePromise(x, promise2, resolve, reject) } catch (e) { reject(e) } }) } if (this.status === PENDING) { // console.log('PENDING'); //订阅所有的成功,失败态 this.onResolveCallback.push(() => { setTimeout(() => { try { let x = onFulfilled(this.value) resolvePromise(x, promise2, resolve, reject) } catch (e) { reject(e) } }) }) this.onRejectCallback.push(() => { setTimeout(() => { try { let x = onRejected(this.fail) resolvePromise(x, promise2, resolve, reject) } catch (e) { reject(e) } }) }) } }) return promise2 } } Promise.resolve=function(callback){ return new Promise((resolve)=>{ resolve(callback) }) } Promise.reject=function(callback){ return new Promise((resolve,reject)=>{ reject(callback) }) } //finally里面要使用resolve是因为要等待callback()执行完成,在执行后续的then方法 Promise.prototype.finally=function(callback){ return this.then(data=>{ return Promise.resolve(callback()).then(()=>data) },err=>{//这里不能使用Promise.reject,因为如果使用了reject,那么就不会等待callback方法执行 return Promise.resolve(callback()).then(()=>err) }) } //判断是否是Promise function isPromise(value){ if(typeof value ==='function' || (typeof value==='object' && value!=null)){ if(typeof value.then==='function'){ return true } } return false } Promise.all=function(values){ return new Promise((resolve,reject)=>{ let arr=[] //计数器,用于计数是否执行完成所有的任务 let num=0 //将返回的值以下标的形式存起来 processData =(key,value)=>{ arr[key]=value if(++num===values.length){ resolve(arr) } } for(let i=0;i<values.length;i++){ let current=values[i] if(isPromise(current)){ current.then(x=>{ processData (i,x) },reject) }else{ processData(i,current) } } }) } Promise.race=function(values){ return new Promise((resolve,reject)=>{ for(let i=0;i<values.length;i++){ let current=values[i] if(isPromise(current)){ current.then(resolve,reject) }else{ resolve(current) } } }) } //测试写的库是否合格promises-aplus-tests Promise.defer = Promise.deferred = function () { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve dfd.reject = reject }) return dfd } module.exports = Promise