1.Promise解决的问题
-
回调嵌套,回调地狱
-
错误捕获不好处理
-
多个异步同步问题 Promise.all
2.版本问题
-
Promise是一个类,默认浏览器高版本或node都是自带Promise的
-
如果低版本没有自带,我们可以使用es6-promise插件
3.promise A+规范
3.1 三个状态
-
Pending等待态
-
fulfilled成功态
-
rejected失败态
只有等待态才能变成成功态/失败态
如果状态变化,不能在修改状态
4.实现简单同步的Promise
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
5.实现简单的异步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
6.链式调用
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
7.resolve的是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)
}
}
8.catch
catch方法是then的语法糖
catch(onRejected){
return this.then(null,onRejected)
}
9.finally
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)
})
}
10.all
异步同步 让所有的异步 并发执行 有序输出
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)
}
}
})
}
11.race
第一个成功就成功,输入第一个结果,第一个失败就失败
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)
})
12.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) => {
//如果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