Promise学习笔记整理

118 阅读9分钟

浅浅的了解Promise

上一篇同步和异步文章中说过js是单线程。js是用于页面交互,如果设计成多线程,一个线程对DOM进行添加操作,另一个线程同时对DOM进行删除操作,这样会让DOM很懵。单线程是为了避免操作DOM冲突。

Promise是ECMAScript6提供的类,为了更加优雅地书写复杂的异步任务。将callback回调方式从层层嵌套方式变成链式操作,使得代码更加清晰,同时更好的处理异步操作的成功与失败。

promise共有三种状态

pending 准备,fulfilled 成功,rejected失败

new Promise() 为pending 准备状态,状态还未确认。

fulfilled 准备状态转变成fulfilled,表示成功状态。一旦确认状态,就无法进行更改。

rejected 准备状态转变成rejected,表示失败状态。一旦确认状态,就无法进行更改。

Promise 的初步使用

Promise只有一个参数,并且这个参数是个函数。函数包含两个参数 resolve 和 reject,而这两个参数也都是个函数,resolve代表成功,reject代表拒绝(失败)。

第一步 new Promise

new Promise()调用了Promise的构造函数,且是立即执行。(上一篇同步和异步文章有介绍相关知识点)

例子:

new Promise((resolve,reject)=>{
        console.log(1)	
})
        console.log(2)

输出结果: 先打印出1,再打印出2

第二步 .then

then方法就是处理状态。一个处理成功函数 一个处理失败函数,可以选择只处理成功或者失败,也可以两个状态一起写入进行处理。

完整写法:

new Promise((resolve,reject)=>{
      //resolve()表示一种状态,成功状态。
	resolve()
}).then(
    //then用于处理状态,上面给出成功或者失败状态,进行处理。
        res=>{
		console.log("成功")
	},
	err=>{
		console.log("失败")
	}
  )
		

输出结果:成功

分析:程序执行到resolve()成功状态,走到then进行处理,因为状态是成功的,处理时走res(名称自己定义)函数,打印成功。如给出的状态是reject()拒绝状态,进入err函数,打印失败。所以then中输出的结果,取决于什么样的状态。

例子:

new Promise((resolve,reject)=>{
        //reject()表示一种状态,拒绝(失败)状态。
        reject()
}).then(
	//then用于处理状态,上面给出成功或者失败状态,进行处理。
	res=>{
                console.log("成功")
	},
	err=>{
                console.log("失败")
	}
)

输出结果:失败

分析:状态为reject失败状态,then就打印err函数结果,Promise中只有两种状态resolve成功和reject失败,两者选其一,then根据状态做出处理。

注:then()有两个参数也是函数,可以写一个参数。如果写一个参数,状态必须为resolve。也就是resolve成功参数必须有,reject参数可以不写。如果不写resolve成功参数,就用null代替。

写一个参数,reject失败状态下返回的结果

例子:

   new Promise((resolve,reject)=>{
	reject()
}).then(
	value=>{
          console.log(1)
	}
)

输出结果: Uncaught (in promise) undefined

写一个参数,resolve成功状态下返回的结果

new Promise((resolve,reject)=>{
	resolve()
}).then(
	value=>{
           console.log(1)
        }
)

输出结果:1

用null占位,成功状态下。

new Promise((resolve,reject)=>{
	resolve()
}).then(
	null,
	value=>{
            console.log("失败")        
	}
)

输出结果:不报错

用null占位,失败状态下。

new Promise((resolve,reject)=>{
	reject()
}).then(
	null,
	value=>{
            console.log("失败")        
	}
)
    

输出结果:失败

then返回值

then返回的是一个Promise

例子:

let  p1 = new Promise((res,err)=>{
        res()
})
				
new Promise((res,err)=>{
        console.log(p1)
}).then(
        res=>{
	console.log("成功")
        },
        err=>{
	console.log("失败")
        }
)

输出结果:Promise {<fulfilled>: undefined}

return 的结果会返回给下一个then,下一个then是对Promise的返回处理

例子:

new Promise((res,err)=>{
       res()
}).then(
    res=>{
	console.log("成功")
	return '这个也成功了'	
    },
    err=>{
	console.log("失败")
     }
     ).then(
        res=>{
                console.log(res)
	},
	err=>{
		console.log(err)
	 }
)

输出结果:成功 这个也成功了

分析:then接收到成功状态进行处理,打印出成功,并将return的返回值传给下一个then,因为是成功状态所以打印出这个也成功了。

例子:

new Promise((res,err)=>{
       res()
}).then(
    res=>{
	console.log("成功")
	return new Promise((res,err)=>{})
    },
    err=>{
	console.log("失败")
     }
).then(
    res=>{
	console.log(1)
     },
    err=>{
	console.log(2)
 }
)

输出结果:成功

分析:then接收到成功状态进行处理,打印出成功,这里return是一个Promise,但是里面没有给出状态,所以第二个then没有等到状态通知,就不会加入微任务队列中,就不会打印出1。

例子:

new Promise((res,err)=>{
       res()
}).then(
    res=>{
		console.log("成功")
		return new Promise((res,err)=>{
			err()
		})
    },
    err=>{
		console.log("失败")
     }
).then(
	res=>{
		console.log(1)
	},
	err=>{
		console.log(2)
	 }
)

输出结果:成功 2

分析:这里return是一个Promise,并且给出了状态,所以第二个then接收到拒绝状态通知,加入微任务队列中,打印出2。

接收的传值

例子:

new Promise((resolve,reject)=>{
    reject("这是失败的")
}).then(
    res=>{
        console.log(res)
    },
    err=>{
        console.log(err)
    }
)

输出结果:这是失败的

分析:then接到的状态是拒绝状态,同时还有值。所以then打印的是reject中的值。

例子:

let data=[12,44,5]

new Promise((resolve,reject)=>{
    resolve(data)
}).then(
    res=>{
        console.log(res)
    },
    err=>{
        console.log("失败")
    }
)

输出结果:数组:12, 44, 5

所以then中的内容可以自定义,也可以接收resolve和reject来传的值。

细节注意

例子:

   new Promise((resolve,reject)=>{
       console.log(1)
   }).then(
        res=>{
           console.log("成功")   
        },
        err=>{
            console.log("失败")        
            }
    )
    

输出结果:1

分析:then没有获取到状态通知,就无法加入到微任务列队中。所以需要加上resolve()或reject(),告诉then状态,才会加入到微任务列队中。虽然不报错,但是程序也不会继续往下走,微任务里就没有这个任务。

Promise单一状态

resolve和reject只能有一种状态存在。

例子:

new Promise((resolve,reject)=>{
    //成功状态
    resolve()
    //失败状态
    reject()
}).then(
    res=>{
        console.log("成功")
    },
    err=>{
        console.log("失败")
    }
)

输出结果:成功

例子:

new Promise((resolve,reject)=>{
    //失败状态
    reject()
    //成功状态
    resolve()
}).then(
    res=>{
        console.log("成功")
    },
    err=>{
        console.log("失败")
    }
)

输出结果:失败

从这两个例子可以看出,两个状态下,最前面的状态起到作用,后面的状态将会是无效。因为程序进入时状态已经发出通知给then,then接到给出的状态,任务就已经加入到微队列中,无法进行改变。

所以Promise是单一的。状态一旦确定下来就不可改变的。

Promise状态中转

例子:

let p1=new Promise((resolve,reject)=>{
    resolve("p1是成功的")
})

new Promise((resolve,reject)=>{
    resolve(p1)
}).then(

    res=>{
        console.log("res:"+res)
    },
    err=>{
        console.log("err:"+err)
    }

)

输出结果:res:p1是成功的

分析:p1返回的是一个Promise,所以传入的就是p1的成功状态。

例子:

let p1=new Promise((resolve,reject)=>{
    reject()
})

new Promise((resolve,reject)=>{
    resolve(p1)
}).then(
    res=>{
        console.log("成功")
    },
    err=>{
        console.log("失败")
    }

)

输出结果:失败

分析:p1是失败状态, resolve(p1)接受的就是拒绝状态,then就走err。

.then() .catch() 和 .finally() 三个方法

Promise 类有 .then() .catch() 和 .finally() 三个方法,这三个方法的参数都是一个函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列

.then()方法

then就是对状态的处理

new Promise((res,err)=>{
       res()
}).then(
    res=>{
		console.log("成功")
    },
    err=>{
		console.log("失败")
     }
)

.catch()方法

catch是对异常进行处理,如果状态是失败情况下,then没有进行失败处理,可以通过catc处理。

例子:

new Promise((res,err)=>{
       err()
}).then(
    res=>{
        console.log("成功")
    }
)

输出结果:控制台报错

分析:失败状态,但是then中没有对失败状态进行处理函数。

例子:

new Promise((res,err)=>{
       err()
}).then(
    res=>{
        console.log("成功")
    }
).catch(err=>{
	console.log("catch异常处理")
})

输出结果:catch异常处理

分析:catch里做了异常处理

catch建议放在最后一个then的后面,对前面的进行统一错误处理,防止遗漏。

.finally()方法

finally方法无论成功还是失败都会执行。

Promise静态方法

resolve() reject() all() race() 四个静态方法

应用场景:如果没有Promise实例,但是还想继续使用reject或resolve。就可以使用Promise.reject()或Promise.resolve()

resolve()成功方法

这里就是默认状态是成功,而不是准备阶段。

例子:

	let p1 = Promise.resolve()
	console.log(p1)

输出结果:Promise {<fulfilled>: undefined}

例子:

	let p1 = Promise.resolve("成功")
	p1.then(
		res=>{
			console.log(res)
		}
	)

输出结果:成功

reject()失败方法

这里就是默认状态是失败,而不是准备阶段。

例子:

	let p1 = Promise.reject("失败")
	p1.catch(
		err=>{
		 console.log(err)
		}
	)

输出结果:失败

all()所有方法

例子:

	let p1 = new Promise((resolve,reject)=>{
		resolve(1)
	})
	
	
	let p2= new Promise((resolve,reject)=>{
		resolve(2)
	})
	
	let p3 = new Promise((resolve,reject)=>{
		resolve(3)
	})
	
	
	Promise.all([p1,p2,p3]).then(res=>{
		console.log(res)
	})

输出结果:1 2 3

分析:Promise.all([p1,p2,p3])中的所有Promise对象都执行结束后再执行。

例子:

	let p1 = new Promise((resolve,reject)=>{
		resolve(1)
	})
	
	
	let p2= new Promise((resolve,reject)=>{
		reject(2)
	})
	
	let p3 = new Promise((resolve,reject)=>{
		resolve(3)
	})
	
	
	Promise.all([p1,p2,p3]).then(res=>{
		console.log(res)
	},err=>{
		console.log("失败"+err)
	})

输出结果:失败2

分析:p2状态是失败的,就进入到err失败处理。p1,p2,p3中有一个失败就无法进入成功处理函数。

race()方法

只要一个完成,就代表都完成。先执行的第一个状态是成功,就进入成功函数,表示都成功了。如果先执行的第一是失败状态,就走异常函数处理。

例子:

	let p1 = new Promise((resolve,reject)=>{
		resolve(1)
	})
	
	
	let p2= new Promise((resolve,reject)=>{
		reject(2)
	})
	
	let p3 = new Promise((resolve,reject)=>{
		resolve(3)
	})
	
	
	Promise.race([p1,p2,p3]).then(res=>{
		console.log(res)
	},err=>{
		console.log("失败"+err)
	})

输出结果:1

例子:

	let p1 = new Promise((resolve,reject)=>{
		resolve(1)
	})
	
	
	let p2= new Promise((resolve,reject)=>{
		reject(2)
	})
	
	let p3 = new Promise((resolve,reject)=>{
		reject(3)
	})
	
	
	Promise.race([p1,p2,p3]).then(res=>{
		console.log(res)
	},err=>{
		console.log("失败"+err)
	})

输出结果:1

分析:先执行的第一个是p1,状态成功。进入then成功函数。

例子:

	let p1 = new Promise((resolve,reject)=>{
		setTimeout(function(){
                       resolve(1)
		},1000)
		
	})
	
	
	let p2= new Promise((resolve,reject)=>{
		reject(2)
	})
	
	let p3 = new Promise((resolve,reject)=>{
		resolve(3)
	})
	
	
	Promise.race([p1,p2,p3]).then(res=>{
		console.log(res)
	},err=>{
		console.log("失败"+err)
	})
            
            

输出结果:失败2

分析:先执行的第一个是p2,失败状态。then走异常处理。

例子:

	let p1 = new Promise((resolve,reject)=>{
		setTimeout(function(){
			resolve(1)
		},1000)
		
	})
	
	
	let p2= new Promise((resolve,reject)=>{
		setTimeout(function(){
			resolve(1)
		},2000)
	})
	
	let p3 = new Promise((resolve,reject)=>{
		resolve(3)
	})
	
	
	Promise.race([p1,p2,p3]).then(res=>{
		console.log(res)
	},err=>{
		console.log("失败"+err)
	})

输出结果:3 分析:p1,p2都加入了定时器,最先执行的是p3,状态为成功。

根据最先执行的状态为准,应用于超时和记时的目的

Promise的优缺点

Promise优点

1.Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API ,统一现在各种各样的 API ,以及不兼容的模式和手法。

2.Promise 更适合处理一次性的结果。

3.链式处理是 Promise。

4.解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。

5.更好的错误处理方式。

Promise缺点

1.一旦确认状态,无法中途取消。

2.如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

3.当处于Pending状态时,无法得知目前进展到哪一个阶段。

4.Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好。

本文章作为学习笔记,如有不对地方,请多多指正,谢谢.