Promise学习笔记

Promise学习笔记

一.Promise是什么?

1.抽象表达:promise是一门新的技术(ES6规范),是js中进行异步编程的新解决方案(旧方案是单纯使用回调函数)
2.具体表达:从语法上说是一个构造函数,从功能上说promise对象用来封装一个异步操作并可以取得成功/失败的结果值。
3.异步编程包括但不限于:
(1)fs文件操作(这个fs时node下面的一个模块 可以对计算机的磁盘进行读写操作)

require('fs').readFile('./index.html',(err,data)=>{})

(2)数据库操作:mongoDB MySQL数据库操作
(3)AJAX网络请求

$.get('/server',(data)=>{})

(4)定时器

setTimeout(()=>{},2000)

由此可见 在promise await async 生成器之前都是使用单纯的回调函数进行异步操作

二.为什么使用Promise?Promise的优点

1.promise使用回调函数更灵活
旧的回调函数必须在启动异步任务前指定好。
promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至能在异步任务结束后指定多个)
2.支持链式调用,可以解决回调地狱问题
(1)回调地狱:回调函数嵌套调用 外部回调函数异步执行的结果是嵌套的回调执行的条件
(2)回调地狱的缺点:不便于阅读 不便于异常处理(每一层在进入异步任务时 都要对错误进行处理 可能会写很多重复性代码)
(3)解决方案:promise链式调用

三.Promise的状态改变

1.状态是Promise实例对象中的一个内置属性(PromiseState),所以我们不能直接对该属性进行操作
2.PromiseState的三个取值/Promise的三个状态:
(1)pending 未决定的
(2)fullfilled/resolved 成功
(3)rejected 失败

3.Promise的状态改变只存在两种可能,且一个promise对象只能改变一次(例如:状态从pending变为resolved后就不能再改变了),无论变为成功或失败都会有一个结果数据,成功的结果数据称为 value , 失败的结果数据称为 reason :
(1)pending->resolved
(2)pending->rejected

四.Promise对象的值——实例对象中的另一个属性PromiseResult

1.PromiseResult中存的是对象成功/失败的结果(异步任务成功/失败的结果)
2.resolve()和reject()这两个函数可以修改PromiseResult中的值。一旦通过这两个函数设置完PromiseResult的值后 在后续的then方法回调中就可以把值取出来 然后对这个值进行相关的操作
在这里插入图片描述
无论成功还是失败 err data都保存在PromiseResult中

五.Promise的基本流程

在这里插入图片描述
首先通过new Promise()创建一个对象 在Promise内部封装异步操作 若异步操作成功 则调用resolve函数 并将Promise对象状态改为fullfilled/resolved 在调用then方法时将调用第一个参数 即第一个回调函数中的代码 返回一个新的Promise对象 若Promise内的异步任务失败了 则调用reject函数 并将Promise对象状态改为rejected 失败后将调用then方法中的第二个回调函数 并返回一个新的Promise对象(then方法的返回是一个新的Promise对象)

六.如何使用Promise

6.1 Promise API

6.1.1 Promise的构造函数:Promise(excutor){}

我们可以通过new Promise来实例化对象 在new时 实例化(Promise)需要接受一个参数excutor excutor被称为执行器函数 excutor是一个函数 可以使用箭头函数/匿名函数等来声明 excutor函数中有两个形参resolve和reject resolve和reject也是两个函数 resolve和reject是内部定义的 异步任务成功调用resolve 失败调用reject
1.excutor函数:执行器(resolve,reject)=>{}
2.resolve函数:内部定义成功时我们调用的函数value=>{}
3.reject函数:内部定义失败时我们调用的函数reason=>{}

说明:executor会在promise内部立即同步调用,异步操作在执行器中执行
在这里插入图片描述
当代码执行到new Promise((resolve,reject)=>{resolve('ok');})时 会立即执行(resolve,reject)=>{resolve('ok');}(resolve,reject)=>{resolve('ok');}中的代码是同步调用的 不会进入队列 会立即执行

<script>
	let p=new Promise((resolve,reject)=>{
    	console.log(111);
    })
    console.log(222);
 </script>
//输出结果为:111 222

6.1.2 Promise.prototype.then方法:(onResolved,onRejected)=>{}

then方法用于指定回调 then中有两个参数onResolved和onRejected onResolved和onRejected都是函数
1.onResolved函数:成功的回调函数(value)=>{}
2.onRejected函数:失败的回调函数(reason)=>{}

说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调 返回一个新的promise对象。

<script>
	let p=new Promise((resolve,reject)=>{
    	let i=1;
        if(i==1){
        	resolve("heihei");
        }
        else{
        	reject("no");
        }
    });
    p.then(value => {
            console.log(value)
        },reason => {
            console.warn(reason);
    })
</script>

6.1.3 Promise.prototype.catch方法:(onRejected)=>{}

catch方法用于指定回调 不过他只能指定失败的回调 内部由then方法实现 相当于: then(undefined, onRejected)。
onRejected函数:失败的回调函数(reason)=>{}

<script>
	let p=new Promise((resolve,reject)=>{
    	let i=2;
        if(i==1){
            resolve("heihei");
        }
        else{
            reject("no");
        }
    });
    
    //使用catch
    p.catch(reason=>{
    	console.log(reason);//输出no
    })
</script>

6.1.4 Promise.resolve方法:(value)=>{}

resolve是promise函数对象的 而非实例对象 resolve接收一个参数value 返回一个Promise 对象 他的作用是为了快速得到一个Promise 对象 可以封装一个值 将这个值转换为Promise 对象
value: 成功的数据或promise对象
说明:如果传入的参数为非Promise类型的对象,则返回的结果为成功的promise对象,如果传入的参数为Promise对象,则参数的结果决定了resolve的结果。

<script>
	//Promise.resolve
    //如果传入的参数为非promise对象,则返回的结果为成功的promise对象
    let p1=Promise.resolve(521);
    console.log(p1);//输出一个promise对象,promiseresult为521,promisestate为fullfilled
          
    //如果传入的参数为promise对象,则参数的结果决定了resolve的结果
    let p2=Promise.resolve(new Promise((resolve,reject)=>{
    	reject('error');
    }))
    console.log(p2); //输出的结果为一个失败的promise对象 promiseresult为error,promisestate为rejected
    //因为是一个失败的promise对象,所以使用catch来捕获,否则报错。我们当前有个失败的promise 没有对应的回调来对这个结果做处理  此时浏览器会报错 所以可以用catch来处理 在catch中传入一个失败的回调 让她对失败的结果做一个处理 
    p2.catch(reason=>{
    	console.log(reason);
    })
          
	let p3=Promise.resolve(new Promise((resolve,reject)=>{
    	resolve('ok');
    }))
    console.log(p3);//输出一个promise对象,promiseresult为ok,promisestate为fullfilled
</script>

6.1.5 Promise.reject方法:(reason)=>{}

reject方法属于promise函数对象的 而非实例对象 reject方法的作用是快速返回一个失败的Promise对象 可以将一个值进行快速的转换 转换成一个Promise类型的数据 只不过这个Promise是失败的 reject方法接收一个参数 无论你传入什么样的参数 返回的都是一个失败的Promise对象 你传入什么 失败的结果就是什么
reason:失败的原因

<script>
	//和promise.resolve类似,如果其传入的参数是一个非promise对象,则它的promiseresult为该参数,如果是一个promise对象,则promiseresult为一个promise对象
    let p1=Promise.reject(521);
    console.log(p1);
 
    //调用了该reject方法,即使参数是一个成功的promise对象也依旧返回一个失败的promise对象
    let p2=Promise.reject(new Promise((resolve,reject)=>{
    	resolve('ok');
    }))
    console.log(p2);
</script>

6.1.6 Promise.all方法;(promises)=>{}

all方法属于promise函数对象的 而非实例对象 all接收一个参数 这个参数一般为Promise组成的数组 也就是说这个参数(数组)中每一个元素都是一个Promise对象
promises: 包含n个promise的数组
说明:返回一个新的promise,只有(参数中)所有的promise都成功,(返回的promise的状态)才成功,只要(参数中的promise)有一个失败了,(返回的promise的状态)就直接失败。成功的结果是每一个promise成功结果组成的数组,失败的结果是在这个数组中失败的那个promise对象失败的结果。

<script>
	let p1=new Promise((resolve,reject)=>{
		resolve('ok');
    })
    let p2=Promise.resolve('ok2');
    let p3=Promise.resolve('ok3');
    const result=Promise.all([p1,p2,p3]);
        
    //下列输出结果是一个成功的promise对象,promiseresult的值为一个数组
    console.log(result);
</script>
<script>
	let p1=new Promise((resolve,reject)=>{
    	resolve('ok');
    })
    let p2=Promise.reject('error');
    let p3=Promise.resolve('ok3');
    const result=Promise.all([p1,p2,p3]);
        
    //下列输出结果是一个失败的promise对象,其结果是p2的失败值
    console.log(result);
</script>

6.1.7 Promise.race方法:(promises)=>{}

race方法属于promise函数对象的 而非实例对象 race接收一个参数 这个参数是一个由promise对象组成的数组 返回的新的promise对象的状态由参数数组中的第一个改变状态的promise状态来决定 第一个改变状态的promise成功则最终返回的promise对象的状态为成功 第一个改变状态的promise失败则最终返回的promise对象的状态为失败
promises:包含n个promise的数组
说明:返回一个新的promise对象,第一个完成的promise的结果状态就是最终状态

<script>
	//p1使用了定时器,所以不是p1第一个完成状态改变
    let p1=new Promise((resolve,reject)=>{
    	setTimeout(()=>{
        	resolve('ok');
        },1000)
    })
    let p2=Promise.resolve('Success');
    let p3=Promise.resolve('ok');
    const result=Promise.race([p1,p2,p3]);
    console.log(result); //输出结果是promise对象,promiseresult为success,因为p2先改变状态
</script>

6.2Promise的几个关键问题

6.2.1 如何改变 promise的状态?

(1) resolve(value):如果当前是pending就会变为resolved。
(2) reject(reason):如果当前是pending就会变为rejected。
(3)抛出异常 throw:如果当前是pending就会变为rejected。

<script>
	let p1 = new Promise((resolve,reject)=>{
		//resolve('success');
        //reject('error');
       //throw 'error';
      })
      console.log(p1);
</script>

6.2.2 一个promise指定多个成功/失败回调函数,都会调用吗?

这个问题相当于:如果我们使用then方法为一个promise方法指定多个回调 这些回调是不是都会执行?
答:当promise对象改变对应状态时 都会调用

<script>
	let p = new Promise((resolve,reject)=>{
		resolve('success');
    })
    // 第一次回调
    p.then(value=>{
    	console.log("yes");
    })
    // 第二次回调
    p.then(value=>{
    	console.log("oh yes");
    })
</script>

在这里插入图片描述
依次执行了两次成功的回调

6.2.3 改变 promise状态和指定回调函数谁先谁后?

改变promise状态:resolve reject throw
指定回调函数:then catch
这个问题可以理解为:代码在运行时 resolve改变状态先执行还是then方法指定回调函数先执行?
1.都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调
当执行器函数中的任务是同步任务 你直接去调resolve的时候 在这种情况下 先改变promise对象的状态 后指定回调

<script>
	let p = new Promise((resolve,reject) => {
		resolve('ok');
	});
	p.then(value => {
		console.log(value);
	},reason => {
		console.log('error');
	})
</script>

当执行器函数中的任务是异步任务时 也就是说我需要等待一段时间才能改变状态 在这种情况下 先执行then方法指定回调 后改变promise对象的状态 在具体使用promise时 这种情况用的比较多

<script>
	let p = new Promise((resolve,reject) => {
		setTimeout(() => {
			resolve('ok');
		},1000)
	});
	p.then(value => {
		console.log(value);
	},reason => {
		console.log('error');
	})
</script>

在上面的代码中 我们延迟1s执行执行器函数中的任务 那么我们可以延迟2s执行then回调函数 此时也是先改变状态再指定回调
2.如何先改状态再指定回调?
(1)在执行器中直接调用resolve()/reject();
(2)延迟更长时间才调用then();
3.什么时候才能得到数据?我的回调函数什么时候才执行?
(1)如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
(2)如果先改变的状态,,那当指定回调时,回调函数就会调用(执行),得到数据

6.2.4 Promise.then()返回的新Promise的结果状态由什么决定?

1.简单表达: then()指定的回调函数执行的结果决定。
2.详细表达:
(1)如果抛出异常,新promise变为rejected,reason为抛出的异常。
(2)如果返回的是非prormise的任意值,新promise变为resolved,value为返回的值。
(3)如果返回的是另一个新promise,此promise的结果就会成为新promise的结果。

<script>
	let p = new Promise((resolve,reject) => {
		resolve('ok');
	});
	let result = p.then(value => {
		//console.log(value);
		//1.抛出错误
		//throw '出了问题';//result的状态会变为失败 promiseresult为'出了问题'
		//2.如果返回的是非prormise类型的对象
		//return 521;//result的状态会变为成功 promiseresult为521
		//3.如果返回的是一个promise类型的对象
		return new Promise((resolve,reject) => {//这个Promise的状态决定了result的状态 这个Promise的结果就是result的结果
			resolve('success');
		})
	},reason => {
		console.warn(reason);
	});
	console.log(result);
</script>

6.2.5 Promise如何串连多个操作任务?

1.promise的then()返回一个新的promise,所以我们可以在then方法后面接着调用then方法,可以看成then()的链式调用。
2.通过then的链式调用串连多个同步/异步任务

<script>
	 let p =new Promise((resolve,reject) => {
          resolve("yes");
     })
     p.then(value => {
          return new Promise((resolve,reject)=>{
              resolve("oh yes~");
          });
     }).then(value => {
          console.log(value);//输出oh yes~
     }).then(value => {
		console.log(value);//输出undefined 因为then的返回结果是一个promise 这个promise的状态由她(then)指定的回调函数的返回值来决定 上一个then没有返回值 没有返回值是undefined 所以上一个then返回的是一个成功的promise 且成功的结果就是你这个返回的结果undefined(promise的值时undefined)既然是成功的 那么就会执行这个then 并输出上一个then成功的结果 即undefined
	})
</script>

6.2.6 Promise 的异常穿透

1.当使用promise的then链式调用时,可以在最后指定失败的回调。
2.前面任何操作出了异常,都会传到最后失败的回调中处理。

<script>
 	let p =new Promise((resolve,reject) => {
         setTimeout(()=>{
            resolve("yes");
         },1000);
     })
     p.then(value => {
          throw 'oh No';
     }).then(value => {
          console.log("123");
     }).then(value => {
          console.log("456");
     }).catch(reason=>{
         console.warn(reason);//输出oh No 输出的是第一个promise中失败的结果的值
     })
</script>

6.2.7 中断 Promise链

1.当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数。
2.办法:在回调函数中返回一个pendding状态的promise对象。

前面我们介绍了promise链 如下所示 下面的代码会打印输出:789 123 456

<script>
 	let p =new Promise((resolve,reject) => {
         setTimeout(()=>{
            resolve("yes");
         },1000);
     })
     p.then(value => {
          console.log("789");
     }).then(value => {
          console.log("123");
     }).then(value => {
          console.log("456");
     }).catch(reason=>{
         console.warn(reason);
     })
</script>

如果我在打印了789之后就不想打印剩下的了 该怎么办?

<script>
 	let p =new Promise((resolve,reject) => {
         setTimeout(()=>{
            resolve("yes");
         },1000);
     })
     p.then(value => {
          console.log("789");
          return new Promise(()=>{});//返回一个pendding状态的promise对象即可中断Promise链 因为这里返回pendding状态的promise对象时 该then方法返回的结果也是一个pendding状态的promise对象 当该then是个pendding状态的promise对象时 后面的then方法的回调就都不能执行了 因为状态没有改变 后面的这些回调函数都不能执行。若你返回的是其他值 如return false 由于false不是promise对象 所以该then方法会返回一个成功的promise对象 该promise对象的结果(promiseresult)是false 下面的then的回调函数都还是会执行。
     }).then(value => {
          console.log("123");
     }).then(value => {
          console.log("456");
     }).catch(reason=>{
         console.warn(reason);
     })
</script>

七. 自定义(手写)Promise

7.1 初始结构搭建

index.html文件

<script>
	let p = new Promise((resolve,reject) => {//这个Promise是全局的Promise对象 由她实例化出来的 现在我们要自定义一个Promise 我们就要覆盖全局的Promise 不用内置的了 我们用我们自己封装的 我们先创建个promise.js 再用script标签把她引进来 在promise.js中定义一个Promise方法 这样 我在这里new的就是promise.js中的Promise而不是全局的了
		// resolve('ok');
		 reject("error");
    });
    p.then(value => {
            console.log(value)
        },reason => {
            console.warn(reason);
        })
</script>

在promise.js文件中 自定义Promise函数并添加then方法

function Promise(executor){

}

// 添加then方法
Promise.prototype.then = function(onResolved,onRejected){
         
}

以下7.2~7.5省略then方法

7.2 resolve与reject结构搭建

执行器函数在内部是同步调用的 所以在Promise内部要写executor() 在index.html中可以发现构造器函数接收了两个参数resolve reject 这两个参数都是函数 所以Promise内部的构造器函数executor() 也要接收两个参数resolve reject 且这两个参数是函数 那么我们就需要在Promise内部定义resolve reject函数
在这里插入图片描述
用户在调用resolve reject函数时传入了参数 所以我们在Promise内部定义resolve reject函数时要给他们加上形参
在这里插入图片描述
本节代码如下:

function Promise(executor){//这个Promise就会覆盖掉全局的Promise
    //自定义resolve函数,名字不一定用resolve 只要这个名字和下面执行器函数中参数的名字一致即可
    function resolve(data){

    }
    //自定义reject函数
    function reject(data){

    }
    //同步调用【执行器函数】
    executor(resolve,reject);
}

7.3 resolve与reject代码实现

resolve函数一执行 Promise的状态(PromiseState)会发生变化 且会设置Promise对象成功的结果(PromiseResult)
PromiseState PromiseResult是实例对象上的一个属性

function Promise(executor){
    //用this为实例对象添加状态属性与结果值属性
    this.PromiseState = 'pending';
    this.PromiseResult = null;
    //保存实例对象的this值
    const that = this;
    //自定义resolve函数,名字不一定用resolve 只要这个名字和下面执行器函数中参数的名字一致即可
    function resolve(data){
    	//this.PromiseState = 'fulfilled'; //这里的this指向window 所以前面要保存实例对象的this
        //改变状态属性
        that.PromiseState = 'fulfilled';  // 或者 resolved 
        //改变结果值属性
        that.PromiseResult = data;
    }
    //自定义reject函数
    function reject(data){
        //改变状态属性
        that.PromiseState = 'rejected';
        //改变结果值属性
        that.PromiseResult = data;
    }
    //同步调用【执行器函数】
    executor(resolve,reject);
}

7.4 throw抛出异常改变状态

try{ }catch(){ } 才能处理throw抛出的异常 异常肯定是在调用执行器函数的时候抛出 所以将executor(resolve,reject);放在try中 catch中的e就是throw抛出的值 所以我们在设置结果值的时候 直接把e给reject就可以了

function Promise(executor){
    //添加状态属性与结果值属性
    this.PromiseState = 'pending';
    this.PromiseResult = null;
    //保存实例对象的this值
    const that = this;
    //自定义resolve函数,名字不一定用resolve 只要这个名字和下面执行器函数中参数的名字一致即可
    function resolve(data){
        //改变状态属性
        that.PromiseState = 'fulfilled';  // 或者 resolved
        //改变结果值属性
        that.PromiseResult =data;
    }
    //自定义reject函数
    function reject(data){
        //改变状态属性
        that.PromiseState = 'rejected';
        //改变结果值属性
        that.PromiseResult =data;
    }
   
    try{
        //同步调用【执行器函数】
        executor(resolve,reject);
    }catch(e){
        //更改Promise对象为失败
        reject(e);
    }
}

index.html文件

<script>
	let p = new Promise((resolve,reject) => {//这个Promise是全局的Promise对象 由她实例化出来的 现在我们要自定义一个Promise 我们就要覆盖全局的Promise 不用内置的了 我们用我们自己封装的 我们先创建个promise.js 再用script标签把她引进来 在promise.js中定义一个Promise方法 这样 我在这里new的就是promise.js中的Promise而不是全局的了
		// resolve('ok');
		// reject("error");
        throw "Error"//try catch时 这个"Error"会传递给e
    });
    p.then(value => {
            console.log(value)
        },reason => {
            console.warn(reason);
        })
</script>

7.5 Promise对象状态只能修改一次

加个判断即可 判断Promise对象的状态之前是不是已经改过了 没改过才改 改过了不改

function Promise(executor){
    //添加状态属性与结果值属性
    this.PromiseState = 'pending';
    this.PromiseResult = null;
    //保存实例对象的this值
    const that = this;
    
    //自定义resolve函数,名字不一定用resolve 只要这个名字和下面执行器函数中参数的名字一致即可
    function resolve(data){
        //判断状态是否修改过,改过就直接返回
        if(that.PromiseState !== 'pending') return;
        //改变状态属性
        that.PromiseState = 'fulfilled';  // 或者 resolve
        //改变结果值属性
        that.PromiseResult =data;
    }
    
    //自定义reject函数
    function reject(data){
        //判断状态是否修改过,改过就直接返回
        if(that.PromiseState !== 'pending') return;
        //改变状态属性
        that.PromiseState = 'rejected';
        //改变结果值属性
        that.PromiseResult =data;
    }

    try{
        //同步调用【执行器函数】
        executor(resolve,reject);
    }catch(e){
        //更改Promise对象为失败
        reject(e);
    }
}

7.6 then方法执行回调

已省略Promise方法的代码
见7.4中的index.html文件中的代码 我们可知 then方法是Promise调用的 所以this指向实例对象p 所以this.PromiseState获取的就是p身上的PromiseState

// 添加then方法
Promise.prototype.then = function(onResolved,onRejected){
    //如果Promise状态为fulfilled回调这个函数
    if(this.PromiseState === 'fulfilled'){
        //将结果值传入
        onResolved(this.PromiseResult);
    }
    //如果Promise状态为rejected回调这个函数
    if(this.PromiseState === 'rejected'){
        //将结果值传入
        onRejected(this.PromiseResult);
    }
}

7.7 异步任务回调的执行

index.html文件代码如下:

<script>
	let p = new Promise((resolve,reject) => {
		setTimeout(() => {
			resolve('ok');
		},1000)
	});
	p.then(value => {
		console.log(value);
	},reason => {
		console.log('error');
	})
</script>

异步任务一般先执行回调才改变状态。所以上一步的代码通过判断PromiseState的状态来决定执行哪个回调函数行不通,解决如下:
回调是什么时候执行的?如果是同步任务 立刻改变了对象的状态 那么在then方法调用时执行回调 若是异步任务 那么在改变状态后再执行回调 改变状态是在Promise构造函数中的reject()方法 resolve()方法中改变的 所以应该在reject()方法 resolve()方法中改变结果值属性后调用回调函数 如何在Promise构造函数中的reject()方法 resolve()方法中调用回调函数呢?他们都不在一个作用域 所以我们在then方法中需要保存回调函数 我们先给Promise对象声明一个属性callback用于保存回调函数 可以用一个全局变量来保存 但是这样不方便不灵活 就好比你把私房钱存在了别人那里 所以最好是保存在自己身上 所以我们给Promise对象声明一个属性callback用于保存回调函数 在then方法中保存回调函数 然后在Promise构造函数中的reject()方法 resolve()方法中调用回调函数

// 自定义函数Promise
 function Promise(executor){
      //添加状态属性与结果值属性
      this.PromiseState = 'pending';
      this.PromiseResult = null;
      // 定义callback属性,保存pending状态的回调函数
      this.callback = {};
       //保存实例对象的this值
       const that = this;
      //自定义resolve函数,名字不一定用resolve
      function resolve(data){
        //判断状态是否修改过
        if(that.PromiseState !== 'pending') return;
         //改变状态属性
         that.PromiseState = 'fulfilled';  // 或者 resolve 
         //改变结果值属性
         that.PromiseResult =data;
         //应该在这里调用成功的回调函数
          //异步任务成功后执行回调函数
          if(that.callback.onResolved){//如果callback中有这个onResolved属性 就执行成功的回调
             that.callback.onResolved(data);
         }
      }
      //自定义reject函数
      function reject(data){
         //判断状态是否修改过,改过就直接返回
        if(that.PromiseState !== 'pending') return;
          //改变状态属性
         that.PromiseState = 'rejected';  
        //改变结果值属性
         that.PromiseResult =data;
         //应该在这里调用失败的回调函数
         //异步任务失败后执行回调函数
         if(that.callback.onRejected){
             that.callback.onRejected(data);
         }
      }

      try{
      //同步调用【执行器函数】
      executor(resolve,reject);
      }catch(e){
          //更改Promise对象为失败
          reject(e);
      }
      
 }
 // 添加then方法
 Promise.prototype.then = function(onResolved,onRejected){
     //如果Promise状态为fulfilled回调这个函数
     if(this.PromiseState === 'fulfilled'){
         //将结果值传入
        onResolved(this.PromiseResult);
     }
     //如果Promise状态为rejected回调这个函数
     if(this.PromiseState === 'rejected'){
         //将结果值传入
        onRejected(this.PromiseResult);
     }
      //如果Promise状态为pending,保存回调函数
      if(this.PromiseState === 'pending'){
        this.callback = {
            onResolved: onResolved,
            onRejected: onRejected
        }
     }
 }

7.8 指定多个回调的实现

在指定多个回调时,如果用7.7写法,最后一个then回调会覆盖掉前面的,我们不能只保存一个回调,如果只保存一个回调的话,最后一个then回调会覆盖掉前面的,所以我们需要将所有的回调都保存下来,解决如下,把保存回调函数的callbacks变为数组,将所有的回调都保存在这个数组中,在调用回调时遍历数组,取出所有的回调执行:

// 自定义函数Promise
function Promise(executor){
	//添加状态属性与结果值属性
    this.PromiseState = 'pending';
    this.PromiseResult = null;
    // 定义callback属性,保存pending状态的回调函数
    this.callbacks = [];
    //保存实例对象的this值
    const that = this;
    //自定义resolve函数,名字不一定用resolve
    function resolve(data){
    	//判断状态是否修改过
    	if(that.PromiseState !== 'pending') return;
    	//改变状态属性
    	that.PromiseState = 'fulfilled';  // 或者 resolve 
    	//改变结果值属性
    	that.PromiseResult =data;
    	//异步任务成功后执行回调函数
    	that.callbacks.forEach(item=>{
    		item.onResolved(data);
        })
     }
     //自定义reject函数
     function reject(data){
     	//判断状态是否修改过,改过就直接返回
     	if(that.PromiseState !== 'pending') return;
     	//改变状态属性
     	that.PromiseState = 'rejected';  
     	//改变结果值属性
     	that.PromiseResult =data;
     	//异步任务失败后执行回调函数
     	that.callbacks.forEach(item=>{
     		item.onRejected(data);
     	})
     }

     try{
     	//同步调用【执行器函数】
     	executor(resolve,reject);
     }catch(e){
     	//更改Promise对象为失败
        reject(e);
     }     
}

// 添加then方法
Promise.prototype.then = function(onResolved,onRejected){
	//如果Promise状态为fulfilled回调这个函数
	if(this.PromiseState === 'fulfilled'){
		//将结果值传入
		onResolved(this.PromiseResult);
	}
	//如果Promise状态为rejected回调这个函数
	if(this.PromiseState === 'rejected'){
		//将结果值传入
		onRejected(this.PromiseResult);
	}
	
	//如果Promise状态为pending,保存回调函数
	if(this.PromiseState === 'pending'){
		this.callbacks.push({
			onResolved: onResolved,
			onRejected: onRejected
		})
	}
}

7.9 同步任务中实现 then()的返回结果

1.同步任务指在执行器函数中 直接通过调resolve(),reject()或者使用throw的方式去改变状态
2.then方法返回结果的规律:then方法的返回结果是由他指定的回调函数的执行结果来决定的 也就是由value => {console.log(value);}reason => {console.log('error');}执行的结果决定 如何实现这个功能?
首先 then方法的返回结果是Promise对象 所以then中所有的代码都应该在return new Promise((resolve, reject) => {}))中 其次我们要获取回调函数执行的结果 根据结果进行后续操作 若结果不是Promise对象 则结果的对象状态为成功 此时需要把then方法的返回结果对象的状态设为成功 那么直接调resolve(result)方法并将回调函数执行的结果作为参数传递进去 这样才能把结果设为回调函数执行的结果 若结果是Promise对象 既然你是个Promise对象 那你一定可以调用then方法 且你的状态如果是成功你一定走then中的第一个回调函数 你的状态就是then方法的返回结果的状态 那么直接调用resolve(v)并将你的结果作为参数传进去就可以啦 你的状态如果是失败同理。如果是使用throw的方式去改变状态 那么需要try catch来捕获
在这里插入图片描述
try catch使用来捕获用户在then函数的第一个回调函数中throw的异常
你第一个回调函数就是onResolved onResolved在try中执行 若onResolved抛出错误 那么try肯定可以捕获到 catch可以拿到你抛出的错误的结果 一旦你抛错 我就要改变返回的Promise对象的状态为失败 所以在catch中直接调用reject(e)并将你抛出的错误作为参数传进去
代码如下 已省略Promise构造函数 省略的函数都是和上一节的一样

// 添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
	return new Promise((resolve, reject) => {
    	//如果Promise状态为fulfilled回调这个函数
        if (this.PromiseState === 'fulfilled') {
        	try {
            	//获取回调函数执行结果
                let result = onResolved(this.PromiseResult);
                //判断
                if (result instanceof Promise) {
                	//如果是Promise对象
                    result.then(v => {
                    	resolve(v);
                    }, r => {
                    	reject(r);
                    })
                 } else {
                 	//结果对象状态为【成功】
                    resolve(result);
                 }
             } catch (e) {
             	reject(e);
             }
        }
        //如果Promise状态为rejected回调这个函数
        if (this.PromiseState === 'rejected') {
        	//将结果值传入
           	onRejected(this.PromiseResult);
        }
        //如果Promise状态为pending,保存回调函数
        if (this.PromiseState === 'pending') {
        	this.callbacks.push({
            	onResolved: onResolved,
                onRejected: onRejected
            })
        }
	})
}

注:instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

7.10 异步任务中实现 then()的返回结果

index.html文件代码如下:

<script>
	let p = new Promise((resolve,reject) => {
		setTimeout(() => {
			resolve('ok');
		},1000)
	});
	//在异步任务中 当new Promise实例化对象完成后 在这里p状态一定是pending状态
	p.then(value => {
		console.log(value);
	},reason => {
		console.log('error');
	})
</script>

在这里插入图片描述
在异步任务中 肯定执行if (this.PromiseState === 'pending') {}中的代码 因为if (this.PromiseState === 'pending') {}中没有调用reject()或resolve()方法 所以then方法返回结果的状态一定是pending 这样是错的 then方法的返回结果应该由他指定的回调函数的执行结果来决定 回调函数最终是在Promise中执行(下面代码中有标注)。在then方法的if (this.PromiseState === 'pending') {}中不能单纯的把onResolved onRejected保存起来 比如在上图中 因为是reject 所以肯定走then中的第二个回调函数 reason => {console.log('error');}会传递给onRejected函数 等状态改变完之后会执行onRejected函数 我们会根据onRejected函数执行结果来改变状态 但我们在onRejected函数中没有调用reject()或resolve()方法 所以此时res的状态一直是pending 做如下修改:
已省略Promise构造函数 省略的函数都是和上一节的一样

     // 添加then方法
     Promise.prototype.then = function (onResolved, onRejected) {
         const that = this;
            return new Promise((resolve, reject) => {
                //如果Promise状态为fulfilled回调这个函数
                if (this.PromiseState === 'fulfilled') {
                    try {
                        //将结果值传入
                        let result = onResolved(this.PromiseResult);
                        //判断
                        if (result instanceof Promise) {
                            //如果是Promise对象
                            result.then(v => {
                                resolve(v);
                            }, r => {
                                reject(r);
                            })
                        } else {
                            //结果对象状态为【成功】
                            resolve(result);
                        }
                    } catch (e) {
                        reject(e);
                    }
                }
                //如果Promise状态为rejected回调这个函数
                if (this.PromiseState === 'rejected') {
                    //将结果值传入
                    onRejected(this.PromiseResult);
                }
                //在异步任务中 肯定来执行下面的代码
                //如果Promise状态为pending,保存回调函数
                if (this.PromiseState === 'pending') {
                    this.callbacks.push({
                        onResolved: function () {
                            try {
                                //执行成功回调函数
                                let result = onResolved(that.PromiseResult);
                                //判断
                                if (result instanceof Promise) {
                                    result.then(v => {
                                        resolve(v);
                                    }, r => {
                                        reject(r);
                                    })
                                } else {
                                    resolve(result);
                                }
                            } catch (e) {
                                reject(e);
                            }
                        },
                        onRejected: function () {
                            try {
                                //执行成功回调函数
                                let result = onRejected(that.PromiseResult);
                                //判断
                                if (result instanceof Promise) {
                                    result.then(v => {
                                        resolve(v);
                                    }, r => {
                                        reject(r);
                                    })
                                } else {
                                    resolve(result);
                                }
                            } catch(e){
                                reject(e);
                            }
                        }
                    })
                }
            })
        }

7.11 then()方法完善与优化

将then方法中的重复代码封装到callback方法中 已省略Promise构造函数 省略的函数都是和上一节的一样

     // 添加then方法
     Promise.prototype.then = function (onResolved, onRejected) {
         const that = this;
            return new Promise((resolve, reject) => {
                //封装重复的部分
                function callback(type){
                    try {
                        //将结果值传入
                        let result = type(that.PromiseResult);
                        //判断
                        if (result instanceof Promise) {
                            //如果是Promise对象
                            result.then(v => {
                                resolve(v);
                            }, r => {
                                reject(r);
                            })
                        } else {
                            //结果对象状态为【成功】
                            resolve(result);
                        }
                    } catch (e) {
                        reject(e);
                    }
                }
                //如果Promise状态为fulfilled回调这个函数
                if (this.PromiseState === 'fulfilled') {
                    callback(onResolved);
                }
                //如果Promise状态为rejected回调这个函数
                if (this.PromiseState === 'rejected') {
                    callback(onRejected);
                }
                //如果Promise状态为pending,保存回调函数
                if (this.PromiseState === 'pending') {
                    this.callbacks.push({
                        onResolved: function () {
                            callback(onResolved);
                        },
                        onRejected: function () {
                            callback(onRejected);
                        }
                    })
                }
            })
        }

7.12 catch()方法-异常穿透与值传递

index.html文件代码如下:

<script>
 	let p = new Promise((resolve,reject) => {
         setTimeout(()=>{
            reject('ok');
         },1000);
     })
     p.then(value => {
          console.log("789");
     }).then(value => {
          console.log("123");
     }).then(value => {
          console.log("456");
     }).catch(reason=>{
         console.warn(reason);
     })
</script>

我们前面的代码无法实现异常穿透 会报错:onRejected is not a function 因为异步任务失败后会执行then中第二个回调函数 执行完new Promise后p一定是pending状态 所以在调用then方法时 会保存回调函数 第一个第二个都要保存 第一个成功的回调函数 她有 第二个失败的回调函数 他没传 就是undefined 当他的状态改完之后 他一定会调回调 调回调的时候发现 回调里面只有成功的回调函数 没有失败的回调函数 失败的回调函数是undefined 此时就会报错 一旦报错 第一个then返回的就是失败的Promise 后面的每个then同理 直到最后catch处理了他们失败的结果 所以产生问题的原因就是 她没有传递第二个回调函数 内置的Promise允许用户在使用then方法时不传第二个回调函数 所以我们在封装时也要允许用户可以不传第二个回调函数 所以在then中我们要判断是否传了回调函数:if(typeof onRejected !== 'function'){onRejected = reason =>{throw reason;}}这行代码相当于加了onRejected = reason =>{throw reason;}这个回调 即:p.then(value => {console.log("789");},reason =>{throw reason;})
在这里插入图片描述
异步回调执行失败后 会返回一个失败的Promise 并抛出失败的异常给下一个then 下一个then中相当于又添加了onRejected = reason =>{throw reason;}这行代码 又返回一个失败的Promise并抛出失败的异常给下一个then 直到最后catch捕获到异常并解决 这样就实现了异常穿透 内置的还可以实现值传递 即第一个回调函数不传也行 如下:以下代码打印222 333
![值传递](https://img-blog.csdnimg.cn/20210420220930751.png
但我们封装的不能实现这个功能 原因和上面一样 异步回调执行成功了 但是在指定回调这里是undefined 状态一改 一执行onResolved 发现onResolved时undefined 所以会报错:onResolved is not a function 所以在封装then时我们也要为onResolved指定默认函数
已省略Promise构造函数 省略的函数都是和上一节的一样

     // 添加then方法
     Promise.prototype.then = function (onResolved, onRejected) {
         const that = this;
         //判断回调参数是否存在
         if(typeof onRejected !== 'function'){
             onRejected = reason =>{
                 throw reason;
             }
         }
         if(typeof onResolved !== 'function'){
             onResolved = value => value;
         }
            return new Promise((resolve, reject) => {
                //封装重复的部分
                function callback(type){
                    try {
                        //将结果值传入
                        let result = type(that.PromiseResult);
                        //判断
                        if (result instanceof Promise) {
                            //如果是Promise对象
                            result.then(v => {
                                resolve(v);
                            }, r => {
                                reject(r);
                            })
                        } else {
                            //结果对象状态为【成功】
                            resolve(result);
                        }
                    } catch (e) {
                        reject(e);
                    }
                }
                //如果Promise状态为fulfilled回调这个函数
                if (this.PromiseState === 'fulfilled') {
                    callback(onResolved);
                }
                //如果Promise状态为rejected回调这个函数
                if (this.PromiseState === 'rejected') {
                    callback(onRejected);
                }
                //如果Promise状态为pending,保存回调函数
                if (this.PromiseState === 'pending') {
                    this.callbacks.push({
                        onResolved: function () {
                            callback(onResolved);
                        },
                        onRejected: function () {
                            callback(onRejected);
                        }
                    })
                }
            })
        }
	//添加catch方法
     Promise.prototype.catch = function(onRejected){
         return this.then(undefined,onRejected);
     }

7.13~7.16只展示要在promise.js中添加的函数 已省略Promise构造函数 then函数 和其他添加的函数 省略的函数都是和上一节的一样 代码汇总见7.17

7.13 resolve方法封装

resolve返回一个Promise对象 他的状态由传入的值来决定 如果传入的是非Promise类型的数据 那他的状态就是成功且传入的参数就是她成功的结果值 如果传入的是Promise类型的对象 则她返回的结果由你传入的Promise类型的对象的状态和结果来决定

//添加resolve方法 resolve是属于Promise函数对象的 不是实例对象
Promise.resolve = function(value){
    //返回promise对象
    return new Promise((resolve,reject) =>{
       if(value instanceof Promise){
            value.then(v=>{
               resolve(v);
            },r=>{
               reject(r);
            })
       }else{
            resolve(value);
       }
    })
}

7.14 reject方法封装

无论传入啥只返回一个失败的promise对象。

//添加reject方法
Promise.reject = function(reason){
    return new Promise((resolve,reject)=>{
        reject(reason);
    });
}

7.15 all方法封装

all()方法返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败。失败了返回那个失败值。

//添加all方法
Promise.all = function(promises){
    return new Promise((resolve,reject) => {
        //添加变量
        let count = 0;
        // 存放成功结果数组
        let arr =[];
        //遍历全部
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(v => {
                //能进到证明其为成功
                count++;
                //保存成功结果
                arr[i]=v;//这里为什么不用push?因为用push可能导致结果的顺序和传图的数组的顺序不相同 因为他们先后改变状态的时间不一定 可能promise[1]先改变状态 他就最先进到数组中了 那他在arr数组中的下标就不再是2 而是0了 
                //如果全部成功
                if (count === promises.length) {
                    //状态改为成功
                    resolve(arr);
                }
            }, r => {
                 //能进到证明其为失败
                reject(r);
            });
        }
    });
}

7.16 race方法封装

//添加race方法
Promise.race = function(promises){
    return new Promise((resolve,reject) => {
        //遍历全部
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(v => {
                    //能进到证明其为成功
                    //状态为成功
                    resolve(v);
                }, r => {
                 //能进到证明其为失败
                reject(r);
            })
         }
      });
    }

7.17 then()方法回调的异步执行

在这里插入图片描述
正常情况下 上述代码的执行结果是111 333 222 因为then中的指定回调是异步执行的 得等同步代码都执行完毕后才执行 但是在我们封装的Promise中 执行结果为111 222 333 如何解决:封装时把回调函数封装成异步的 用定时器包裹一下就好了 所以在then方法中 当Promise状态为fulfilled rejected时将回调函数设置成异步的 在Promise构造函数中 resolve reject执行回调函数时也需要将回调函数设成异步的

	// 自定义函数Promise
	function Promise(executor){
          //添加状态属性与结果值属性
          this.PromiseState = 'pending';
          this.PromiseResult = null;
          // 定义callback属性,保存pending状态的回调函数
          this.callbacks = [];
           //保存实例对象的this值
           const that = this;
          //自定义resolve函数,名字不一定用resolve
          function resolve(data) {
        //判断状态是否修改过
        if (that.PromiseState !== 'pending') return;
        //改变状态属性
        that.PromiseState = 'fulfilled';  // 或者 resolve 
        //改变结果值属性
        that.PromiseResult = data;
        //异步任务成功后执行回调函数
        setTimeout(() => {
            that.callbacks.forEach(item => {
                item.onResolved(data);
            })
        });
    }
    //自定义reject函数
    function reject(data) {
        //判断状态是否修改过,改过就直接返回
        if (that.PromiseState !== 'pending') return;
        //改变状态属性
        that.PromiseState = 'rejected';
        //改变结果值属性
        that.PromiseResult = data;
        //异步任务失败后执行回调函数
        setTimeout(() => {
            that.callbacks.forEach(item => {
                item.onRejected(data);
            })
        });
    }

          try{
          //同步调用【执行器函数】
          executor(resolve,reject);
          }catch(e){
              //更改Promise对象为失败
              reject(e);
          }
          
     }
     // 添加then方法
     Promise.prototype.then = function (onResolved, onRejected) {
         const that = this;
         //判断回调参数是否存在
         if(typeof onRejected !== 'function'){
             onRejected = reason =>{
                 throw reason;
             }
         }
         if(typeof onResolved !== 'function'){
             onResolved = value => value;
         }
            return new Promise((resolve, reject) => {
                //封装重复的部分
                function callback(type){
                    try {
                        //将结果值传入
                        let result = type(that.PromiseResult);
                        //判断
                        if (result instanceof Promise) {
                            //如果是Promise对象
                            result.then(v => {
                                resolve(v);
                            }, r => {
                                reject(r);
                            })
                        } else {
                            //结果对象状态为【成功】
                            resolve(result);
                        }
                    } catch (e) {
                        reject(e);
                    }
                }
                //如果Promise状态为fulfilled回调这个函数
                if (this.PromiseState === 'fulfilled') {
                    setTimeout(()=>{
                        callback(onResolved);
                    });
                }
                //如果Promise状态为rejected回调这个函数
                if (this.PromiseState === 'rejected') {
                    setTimeout(()=>{
                        callback(onRejected);
                    });
                }
                //如果Promise状态为pending,保存回调函数
                if (this.PromiseState === 'pending') {
                    this.callbacks.push({
                        onResolved: function () {
                            callback(onResolved);
                        },
                        onRejected: function () {
                            callback(onRejected);
                        }
                    })
                }
            })
        }
        
//添加catch 方法
Promise.prototype.catch = function(onRejected){
	return this.then(undefined,onRejected);
}
     
//添加resolve方法
Promise.resolve = function(value){
	//返回promise对象
    return new Promise((resolve,reject) =>{
       if(value instanceof Promise){
            value.then(v=>{
               resolve(v);
            },r=>{
               reject(r);
            })
       }else{
            resolve(value);
       }
    })
}
//添加reject方法
Promise.reject = function(reason){
    return new Promise((resolve,reject)=>{
        reject(reason);
    });
}
//添加all方法
Promise.all = function(promises){
    return new Promise((resolve,reject) => {
        //添加变量
        let count = 0;
        // 存放成功结果数组
        let arr =[];
        //遍历全部
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(v => {
                //能进到证明其为成功
                count++;
                //保存成功结果
                arr[i]=v;
                //如果全部成功
                if (count === promises.length) {
                    //状态为成功
                    resolve(arr);
                }
            }, r => {
                 //能进到证明其为失败
                reject(r);
            });
        }
    });
}
//添加race方法
Promise.race = function(promises){
    return new Promise((resolve,reject) => {
        //遍历全部
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(v => {
                    //能进到证明其为成功
                    //状态为成功
                    resolve(v);
                }, r => {
                 //能进到证明其为失败
                reject(r);
            })
         }
      });
    }

7.18 class版本的实现

class Promise {
    //构造方法
    constructor(executor) {
        //添加状态属性与结果值属性
        this.PromiseState = 'pending';
        this.PromiseResult = null;
        // 定义callback属性,保存pending状态的回调函数
        this.callbacks = [];
        //保存实例对象的this值
        const that = this;

        //自定义resolve函数,名字不一定用resolve
        function resolve(data) {
            //判断状态是否修改过
            if (that.PromiseState !== 'pending') return;
            //改变状态属性
            that.PromiseState = 'fulfilled';  // 或者 resolve
            //改变结果值属性
            that.PromiseResult = data;
            //异步任务成功后执行回调函数
            setTimeout(() => {
                that.callbacks.forEach(item => {
                    item.onResolved(data);
                })
            });
        }

        //自定义reject函数
        function reject(data) {
            //判断状态是否修改过,改过就直接返回
            if (that.PromiseState !== 'pending') return;
            //改变状态属性
            that.PromiseState = 'rejected';
            //改变结果值属性
            that.PromiseResult = data;
            //异步任务失败后执行回调函数
            setTimeout(() => {
                that.callbacks.forEach(item => {
                    item.onRejected(data);
                })
            });
        }

        try {
            //同步调用【执行器函数】
            executor(resolve, reject);
        } catch (e) {
            //更改Promise对象为失败
            reject(e);
        }
    }

//then方法封装
    then(onResolved, onRejected) {
        const that = this;
        //判断回调参数是否存在
        if (typeof onRejected !== 'function') {
            onRejected = reason => {
                throw reason;
            }
        }
        if (typeof onResolved !== 'function') {
            onResolved = value => value;
        }
        return new Promise((resolve, reject) => {
            //封装重复的部分
            function callback(type) {
                try {
                    //将结果值传入
                    let result = type(that.PromiseResult);
                    //判断
                    if (result instanceof Promise) {
                        //如果是Promise对象
                        result.then(v => {
                            resolve(v);
                        }, r => {
                            reject(r);
                        })
                    } else {
                        //结果对象状态为【成功】
                        resolve(result);
                    }
                } catch (e) {
                    reject(e);
                }
            }

            //如果Promise状态为fulfilled回调这个函数
            if (this.PromiseState === 'fulfilled') {
                setTimeout(() => {
                    callback(onResolved);
                });
            }
            //如果Promise状态为rejected回调这个函数
            if (this.PromiseState === 'rejected') {
                setTimeout(() => {
                    callback(onRejected);
                });
            }
            //如果Promise状态为pending,保存回调函数
            if (this.PromiseState === 'pending') {
                this.callbacks.push({
                    onResolved: function () {
                        callback(onResolved);
                    },
                    onRejected: function () {
                        callback(onRejected);
                    }
                })
            }
        })
    }

//catch 方法
    catch(onRejected) {
        return this.then(undefined, onRejected);
    }

//resolve方法 不属于示例对象 它属于类 也就是我们这个构造函数Promise 所以我们需要用static作为关键字对他进行描述 表明这是个静态成员 它属于类而不属于实例对象
    static resolve(value) {
        //返回promise对象
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                })
            } else {
                resolve(value);
            }
        })
    }

//reject方法
    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason);
        });
    }

//all方法
    static all(promises) {
        return new Promise((resolve, reject) => {
            //添加变量
            let count = 0;
            // 存放成功结果数组
            let arr = [];
            //遍历全部
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(v => {
                    //能进到证明其为成功
                    count++;
                    //保存成功结果
                    arr[i] = v;
                    //如果全部成功
                    if (count === promises.length) {
                        //状态为成功
                        resolve(arr);
                    }
                }, r => {
                    //能进到证明其为失败
                    reject(r);
                });
            }
        });
    }

//race方法
    static race(promises) {
        return new Promise((resolve, reject) => {
            //遍历全部
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(v => {
                    //能进到证明其为成功
                    //状态为成功
                    resolve(v);
                }, r => {
                    //能进到证明其为失败
                    reject(r);
                })
            }
        });
    }
}

7.19 封装Promise.all

思路:

  1. 接收一个 Promise 实例的数组
  2. 遍历每一个数组元素,如果元素不是 Promise 对象,则使用 Promise.resolve 转成 Promise 对象
  3. 如果全部成功,状态变为 resolved,返回值将组成一个数组传给回调
  4. 只要有一个失败,状态就变为 rejected,返回值将直接传递给回调all() 的返回值也是新的 Promise 对象
function promiseAll(promises) {
	// promiseAll返回的是一个promise 所以才能在promiseAll后面.then和.catch 
	// 所以我们要先new一个promise示例
	return new Promise((resolve, reject) => {
		if (!Array.isArray(promises)) {// 判断参数是不是数组
        	return reject(new TypeError('arguments must be an array'));
        }
        var resolvedCounter = 0;// 计数器 用于统计返回了多少个fulfilled
        var promiseNum = promises.length;// 统计传入的数组的长度
        var resolvedValues = new Array(promiseNum);// 创建新数组 数组长度是传入的数组的长度
        // 这个数组用来存放所有promise的返回值(执行成功的结果)
        for (let i = 0; i < promiseNum; i++) {// 遍历传入的数组
        	// 我怕传入的数组中的元素不是promise 
        	// 所以我用Promise.resolve将他包裹一下使她成为一个promise
        	// Promise.resolve(promises[i])返回的是fulfilled 则执行then中第一个回调函数
        	Promise.resolve(promises[i]).then(value => {
            	resolvedCounter++;// 计数器++
        		resolvedValues[i] = value;// 将当前返回值存入空数组中
        		if (resolvedCounter == promiseNum) {
        			// 传入的promise都是fulfilled 将resolvedValues作为resolved的参数返回
       				return resolve(resolvedValues)
        			//我们在外层通过调用promiseAll 在then中就可以拿到resolvedValues
       			}
        	}, reason => {
        		// Promise.resolve(promises[i])返回的是rejected 则执行这个回调函数
        		// 若第一个promise的返回结果是rejected 
        		// 则直接将第一个promise的执行结果作为reject的参数返回 
        		// 后面的promise都不会执行
               return reject(reason)
          	})
     	}
	})
}

7.19 封装Promise.race

思路:返回一个创建的promise,在该promise的then中遍历每一个数组元素,并且当某个元素有返回,直接执行创建的promise的resolve/reject

function promiseRace(promises) {
	if (!Array.isArray(promises)) {//判断传入的参数是不是数组
		throw new Error("promises must be an array")
    }
    // race返回的也是一个promise 所以才能在Promise后面.then和.catch
    return new Promise(function (resolve, reject) {
    	for (let i = 0; i < promiseNum; i++) {
			// 遍历传入的数组 数组中不管哪个promise执行成功或执行失败都会影响返回的Promise的状态
        	// 一旦这个状态拿到了之后就定格了不变了 所以可以实现拿到数组中最先执行的promise的值 
        	// 他就是把每个promise都执行了 执行之后把外层Promise中的resolve和reject 
        	// 在他们分别成功或失败时再去执行 虽然有多个promise 但最终走的我外层的Promise 
        	// 这个外层的Promise决定我当前执行是否结束
        	Promise.resolve(promises[i]).then(value => {
				resolve(value);
            }, reason => {
            	reject(reason);
            })
      	)
  	})
}

八.async

MDN文档
1.async用来标识函数 形成async函数
2.async函数也是一个函数 只不过他的返回值时一个Promise对象
3.Promise对象的结果由async函数执行的返回值决定。
4.async函数的返回结果跟 then()方法返回结果是一样的
在这里插入图片描述

九.await

MDN文档
1.await右侧的表达式一般为promise对象,但也可以是其它的值。
2.如果表达式是promise对象,await返回的是promise成功的值。
3.如果表达式是其它值,直接将此值作为await的返回值。
4.await主要是获取promise对象成功的结果 如果promise对象失败的话就通过try catch 在catch中拿到失败的结果

注意:
1.await 必须写在async函数中,但async 函数中可以没有await 。
2.如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理。
在这里插入图片描述

十.async和await结合实践

需求:将resource文件夹下面的1.html 2.html 3.html文件中的内容获取并拼接 然后打印输出拼接结果
用promise来做 代码如下:
在这里插入图片描述
用async与await来做 代码如下:

//util中有一个方法可以将API转换成promise形式的函数 
const util = require('util');
const mineReadFile = util.promisefy(fs.readFile);

async function main(){
	try{
		let data1 = await mineReadFile('./resource/1.html')//读取第一个文件的内容
		let data2 = await mineReadFile('./resource/2.html')//读取第二个文件的内容
		let data3 = await mineReadFile('./resource/3.html')//读取第三个文件的内容
		console.log(data1 + data2 + data3);
	}catch(e){
		console.log(e);
	}
}
main()

十一.async与await结合发生ajax请求

需求:点击按钮获取一句名言。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn">获取一句名言</button>
    <script>
        function sendAJAX(url) {
         return new Promise((resolve, reject) => {
                //创建对象
                const xhr = new XMLHttpRequest();
                xhr.responseType = 'json';
                //初始化
                xhr.open('GET', url);
                //发送
                xhr.send();
                //处理响应结果
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        if (xhr.status >= 200 && xhr.status < 300) {
                            //输出响应体
                            resolve(xhr.response);
                        } else {
                            //输出响应状态码
                            reject(xhr.status);
                        }
                    }
                }
            });
     }
         
        var btn = document.querySelector("#btn");
        btn.addEventListener('click',async function(){
             let word = await sendAJAX("http://poetry.apiopen.top/sentences");
              console.log(word);
        })
    </script>
</body>
</html>

defer和async区别

defer会在文档解析完之后执行 并且多个defer会按照顺序执行 而async则是在js加载好之后就会执行 并且有多个async时 哪个加载好就执行哪个

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值