什么是promise
Promise是异步编程的一种解决方案,promise就是一个对象,它可以获取异步操作的消息。从本意上讲,它是承诺,承诺过一段时间给你一个结果。 promise有三种状态:pedding(等待),fulfiled(成功),rejected(失败)。状态一旦改变,就不会在变。创造promise实例后,它会立即执行。
之前刚学习node的时候,会经常见到一个单词,callback,每一个异步里面都嵌套一个回调,当时有一些情况下其实就遇到了回调地狱的问题,也感觉到这样是有问题的,但是并没有去想怎么去解决。
promise就是用来解决这样的问题的:
- 回调地狱,代码难以维护,常常第一个函数的输出是第二个函数的输入这种现象
- promise可以支持多个并发的请求,获取并发请求中的数据
- 这个promise可以解决异步的问题,本身不能说promise是异步的
怎么用promise
首先,我们来先看最基本的用法,new一个peomise对象
let p = new Promise((resolve, reject) => {//异步操作setTimeout(() => {console.log('成功')resolve('成功')}, 1000)})
promise构造函数接受一个参数,函数,这个函数要传入两个参数
- resolve:异步操作执行成功后的回调函数
- reject:异步操作执行失败后的回调函数
链式操作
promise的精髓是状态,用维护状态,传递状态的放式来使得回调函数能够被即使调用,比传递callback函数要简单灵活。而promise真正的用法是在then的链式调用上面,这才是解决回调地狱的关键所在
p.then(data => {console.log(data)}).then(data => {console.log(data)}).then(data => {console.log(data)})
reject
上面我们只是看了promise成功的状态,而失败的回调呢?
let p = new Promise((resolve, reject) => {//做一些异步操作setTimeout(function(){var num = Math.ceil(Math.random()*10); //生成1-10的随机数if(num<=5){resolve(num);}else{reject('数字太大了');}}, 2000);});p.then((data) => {console.log('resolved',data);},(err) => {console.log('rejected',err);});
我们知道promise构造函数中的函数接收两个参数,resolve是成功的回调,reject就是失败的回调。在then中,一样接受两个参数,一个是resolve成功的回调,一个是reject失败的回调。
catch
promise对象除了then方法之外,还有catch方法。catch我们是了解的,在promise中的用法也是一样的,运行中的错误就会被捕获到catch中
p.then((data) => {console.log('resolved',data);console.log(somedata); //此处的somedata未定义}).catch((err) => {console.log('rejected',err);});
本来我们去访问一个不存在的变量,会直接报错,程序停止。但是在promise中错误被抛出,然后再catch中,捕获错误。和try catch的功能相同
all
当我们有多个异步方法,他们的执行顺序并没有强制的要求,可以同时的去调用。这时候可以用promise的all方法。all方法接受一个数组,数组包含每一个异步操作的promise对象。
let Promise1 = new Promise(function(resolve, reject){})let Promise2 = new Promise(function(resolve, reject){})let Promise3 = new Promise(function(resolve, reject){})let p = Promise.all([Promise1, Promise2, Promise3])p.then(funciton(){// 三个都成功则成功}, function(){// 只要有失败,则失败})
all方法需要数组中的promise全部执行成功才会进入到成功状态,否则就是失败。
race
race方法和all一样,都是去并发请求多个异步操作,不同的是,all是全成功则成功,而race事看第一个返回的异步的状态,第一个成功则成功,第一个失败则失败
//请求某个图片资源function requestImg(){var p = new Promise((resolve, reject) => {var img = new Image();img.onload = function(){resolve(img);}img.src = '图片的路径';});return p;}//延时函数,用于给请求计时function timeout(){var p = new Promise((resolve, reject) => {setTimeout(() => {reject('图片请求超时');}, 5000);});return p;}Promise.race([requestImg(), timeout()]).then((data) =>{console.log(data);}).catch((err) => {console.log(err);});
实现自己的promise
成功失败的回调方法
class Promise {constructor (executor){//默认状态是等待状态this.status = 'pending';this.value = undefined;this.reason = undefined;//存放成功的回调this.onResolvedCallbacks = [];//存放失败的回调this.onRejectedCallbacks = [];let resolve = (data) => {//this指的是实例if(this.status === 'pending'){this.value = data;this.status = "resolved";this.onResolvedCallbacks.forEach(fn => fn());}}let reject = (reason) => {if(this.status === 'pending'){this.reason = reason;this.status = 'rejected';this.onRejectedCallbacks.forEach(fn => fn());}}try{//执行时可能会发生异常executor(resolve,reject);}catch (e){reject(e);//promise失败了}}
then方法
then(onFulFilled, onRejected) {if (this.status === 'resolved') {onFulFilled(this.value);}if (this.status === 'rejected') {onRejected(this.reason);}// 当前既没有完成 也没有失败if (this.status === 'pending') {// 存放成功的回调this.onResolvedCallbacks.push(() => {onFulFilled(this.value);});// 存放失败的回调this.onRejectedCallbacks.push(() => {onRejected(this.reason);});}}
链式调用
function resolvePromise(promise2,x,resolve,reject){//判断x是不是promise//规范中规定:我们允许别人乱写,这个代码可以实现我们的promise和别人的promise 进行交互if(promise2 === x){//不能自己等待自己完成return reject(new TypeError('循环引用'));};// x是除了null以外的对象或者函数if(x !=null && (typeof x === 'object' || typeof x === 'function')){let called;//防止成功后调用失败try{//防止取then是出现异常 object.definePropertylet then = x.then;//取x的then方法 {then:{}}if(typeof then === 'function'){//如果then是函数就认为他是promise//call第一个参数是this,后面的是成功的回调和失败的回调then.call(x,y => {//如果Y是promise就继续递归promiseif(called) return;called = true;resolvePromise(promise2,y,resolve,reject)},r => { //只要失败了就失败了if(called) return;called = true;reject(r);});}else{//then是一个普通对象,就直接成功即可resolve(x);}}catch (e){if(called) return;called = true;reject(e)}}else{//x = 123 x就是一个普通值 作为下个then成功的参数resolve(x)}}then(onFulFilled, onRejected) {onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : y => yonRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }let promise2if(this.status === FULFILLED) {promise2 = new Promise((resolve, reject) => {setTimeout(() => {try {let x = onFulFilled(this.value)resolvePromise(promise2, x, resolve, reject)}catch(e) {reject(e)}}, 0)})// console.log('resolve then...', this.value)// onFulFilled(this.value)}if(this.status === REJECTED) {promise2 = new Promise((resolve, reject) => {setTimeout(() => {try {let x = onRejected(this.value)resolvePromise(promise2, x, resolve, reject)}catch(e) {reject(e)}}, 0)})// console.log('reject then...', this.reason)// onRejected(this.reason)}if(this.status === PENDING) {promise2 = new Promise((resolve, reject) => {this.onResolvedCallbacks.push(() => {setTimeout(() => {try{let x = onFuiFilled(this.value);resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}},0)})this.onRejectedCallbacks.push(() => {setTimeout(() => {try{let x = onRejected(this.reason);resolvePromise(promise2,x,resolve,reject)}catch(e){reject(e)}},0)})})// console.log('pedding then...', this.value, this.reason)}return promise2}
catch方法
catch(onRejected) {return this.then(null, onRejected)}
all, race,resolve, reject实现
// 只要有一个promise成功了 就算成功。如果第一个失败了就失败了Promise.race = function (promises) {return new Promise((resolve, reject) => {for (var i = 0; i < promises.length; i++) {promises[i].then(resolve,reject)}})}// 生成一个成功的promisePromise.resolve = function(value){return new Promise((resolve,reject) => resolve(value)}// 生成一个失败的promisePromise.reject = function(reason){return new Promise((resolve,reject) => reject(reason))}
