promise

初体验

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>基本使用</title>
	<link crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
	<div class="container">
			<h2 class="page-header">Promise 初体验</h2>
			<button class="btn btn-primary" id="btn">点击抽奖</button>
	</div>
	<script>
		//生成随机数
		function rand(m,n){
			return Math.ceil(Math.random() * (n-m+1)) + m-1;
		}
		/**
			点击按钮,  1s 后显示是否中奖(30%概率中奖)
				若中奖弹出    恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
				若未中奖弹出  再接再厉
		*/
		//获取元素对象
		const btn = document.querySelector('#btn');
		//绑定单击事件
		btn.addEventListener('click', function(){
			//定时器
			// setTimeout(() => {
			//     //30%  1-100  1 2 30
			//     //获取从1 - 100的一个随机数
			//     let n = rand(1, 100);
			//     //判断
			//     if(n <= 30){
			//         alert('恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券');
			//     }else{
			//         alert('再接再厉');
			//     }
			// }, 1000);

			//Promise 形式实现
			// resolve 解决  函数类型的数据
			// reject  拒绝  函数类型的数据
			const p = new Promise((resolve, reject) => {
				setTimeout(() => {
					//30%  1-100  1 2 30
					//获取从1 - 100的一个随机数
					let n = rand(1, 100);
					//判断
					if(n <= 30){
							resolve(n); // 将 promise 对象的状态设置为 『成功』
					}else{
							reject(n); // 将 promise 对象的状态设置为 『失败』
					}
				}, 1000);
			});

			console.log(p);
			//调用 then 方法
			// value 值
			// reason 理由
			p.then((value) => {
				alert('恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券, 您的中奖数字为 ' + value);
			}, (reason) => {
				alert('再接再厉, 您的号码为 ' + reason);
			});

		});

	</script>
</body>

</html>

fs读取文件

//
const fs = require('fs');

//回调函数 形式
// fs.readFile('./resource/content.txt', (err, data) => {
//     // 如果出错 则抛出错误
//     if(err)  throw err;
//     //输出文件内容
//     console.log(data.toString());
// });

//Promise 形式
let p = new Promise((resolve , reject) => {
    fs.readFile('resource\\content.txt', (err, data) => {
        //如果出错
        if(err) reject(err);
        //如果成功
        resolve(data);
    });
});

//调用 then 
p.then(value=>{
    console.log(value.toString());
}, reason=>{
    console.log(reason);
});

Ajax请求

<body>
	<div class="container">
		<h2 class="page-header">Promise 封装 AJAX 操作</h2>
		<button class="btn btn-primary" id="btn">点击发送 AJAX</button>
	</div>
	<script>
		//接口地址 https://api.apiopen.top/getJoke
		//获取元素对象
		const btn = document.querySelector('#btn');

		btn.addEventListener('click', function () {
			//创建 Promise
			const p = new Promise((resolve, reject) => {
				//1.创建对象
				const xhr = new XMLHttpRequest();
				//2. 初始化
				xhr.open('GET', 'https://api.apiopen.top/getJoke');
				//3. 发送
				xhr.send();
				//4. 处理响应结果
				xhr.onreadystatechange = function () {
					if (xhr.readyState === 4) {
						//判断响应状态码 2xx   
						if (xhr.status >= 200 && xhr.status < 300) {
							//控制台输出响应体
							resolve(xhr.response);
						} else {
							//控制台输出响应状态码
							reject(xhr.status);
						}
					}
				}
			});
			//调用then方法
			p.then(value => {
				console.log(value);
			}, reason => {
				console.warn(reason);
			});
		});
	</script>
</body>

封装fs读取文件操作

/**
 * 封装一个函数 mineReadFile 读取文件内容
 * 参数:  path  文件路径
 * 返回:  promise 对象
 */
function mineReadFile(path){
    return new Promise((resolve, reject) => {
        //读取文件 require('fs')node核心模块
        require('fs').readFile(path, (err, data) =>{
            //判断
            if(err) reject(err);
            //成功
            resolve(data);
        });
    });
}

mineReadFile('./resource/content.txt')
.then(value=>{
    //输出文件内容
    console.log(value.toString());
}, reason=>{
    console.log(reason);
});

util.promisify方法进行promise风格转换

/**
 * util.promisify 方法
 * 传入一个遵循常见的错误优先的回调风格的函数
 * (即以(err,value)=> ...回调作为最后一个参数
 * 并返回一个返回promise的版本
 */
//引入 util 模块
const util = require('util');
//引入 fs 模块
const fs = require('fs');
//返回一个新的函数
let mineReadFile = util.promisify(fs.readFile);

mineReadFile('./resource/content.txt').then(value=>{
    console.log(value.toString());
});

Promise封装Ajax

<body>
	<script>
		/**
		 * 封装一个函数 sendAJAX 发送 GET AJAX 请求
		 * 参数   URL
		 * 返回结果 Promise 对象
		 */
		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);
						}
					}
				}
			});
		}

		sendAJAX('https://api.apiopen.top/getJoke')
			.then(value => {
				console.log(value);
			}, reason => {
				console.warn(reason);
			});
	</script>
</body>

Promise 的状态

实例对象中的一个属性 『PromiseState』

  • pending 未决定的
  • resolved / fullfilled 成功
  • rejected 失败

Promise 对象的值

实例对象中的另一个属性 『PromiseResult』
保存着异步任务『成功/失败』的结果

  • resolve
  • reject

Promise的API

  • Promise.resolve
<script>
   //
   let p1 = Promise.resolve(521);
   //如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
   //如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
   let p2 = Promise.resolve(new Promise((resolve, reject) => {
       // resolve('OK');
       reject('Error');
   }));
   // console.log(p2);
   p2.catch(reason => {
       console.log(reason);
   })
</script>
  • Promise.reject
   <script>
       // 返回一个失败的promise对象
       // let p = Promise.reject(521);
       // let p2 = Promise.reject('iloveyou');
       let p3 = Promise.reject(new Promise((resolve, reject) => {
           resolve('OK');
       }));
       
       console.log(p3);
   </script>
  • Promise.all
 <script>
     let p1 = new Promise((resolve, reject) => {
         resolve('OK');
     })
     // let p2 = Promise.resolve('Success');
     let p2 = Promise.reject('Error');
     let p3 = Promise.resolve('Oh Yeah');
     
     //返回一个新的promise,只有所有的promise都成功了才成功,只要有一个失败了就直接失败
     const result = Promise.all([p1, p2, p3]);

     console.log(result);
 </script>
  • Promise.race
   <script>
       let p1 = new Promise((resolve, reject) => {
           setTimeout(() => {
               resolve('OK');
           }, 1000);
       })
       let p2 = Promise.resolve('Success');
       let p3 = Promise.resolve('Oh Yeah');

       //返回一个新的promise 第一个完成的promise结果状态就是最终的结果状态
       const result = Promise.race([p1, p2, p3]);

       console.log(result);
   </script>

关键问题

  • 修改promise状态
  let p = new Promise((resolve, reject) => {
      //1. resolve 函数
      // resolve('ok'); // pending   => fulfilled (resolved)
      //2. reject 函数
      // reject("error");// pending  =>  rejected 
      //3. 抛出错误
      // throw '出问题了';
  });

  console.log(p);
  • 一个promise指定多个成功/失败回调函数,当promise改变为对应状态时都会调用
   let p = new Promise((resolve, reject) => {
       // resolve('OK');
   });

   ///指定回调 - 1
   p.then(value => {
       console.log(value);
   });

   //指定回调 - 2
   p.then(value => {
       alert(value);
   });
  • 改变promise状态和指定回调函数谁先谁后
    都有可能
    如何先改状态再执行回调
    (1)在执行器中直接调用resolve()/reject()
    (2)延迟更长的时间才调用then()
    什么时候才能得到数据
    (1)先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
    (2)如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
  • 异常穿透
    当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
    前面任何操作出了异常, 都会传到最后失败的回调中处理
  let p = new Promise((resolve, reject) => {
      setTimeout(() => {
          resolve('OK');
          // reject('Err');
      }, 1000);
  });

  p.then(value => {
      // console.log(111);
      throw '失败啦!';
  }).then(value => {
      console.log(222);
  }).then(value => {
      console.log(333);
  }).catch(reason => {
      console.warn(reason);
  });
  • 中断 promise 链
    当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数 办法: 在回调函数中返回一个 pendding 状态的 promise 对象
  let p = new Promise((resolve, reject) => {
      setTimeout(() => {
          resolve('OK');
      }, 1000);
  });

  p.then(value => {
      console.log(111);
      //有且只有一个方式
      return new Promise(() => {});
  }).then(value => {
      console.log(222);
  }).then(value => {
      console.log(333);
  }).catch(reason => {
      console.warn(reason);
  });

async函数

    <script>
        //then
        async function main(){
            //1. 如果返回值是一个非Promise类型的数据->返回成功的promise对象
            // return 521;
            //2. 如果返回的是一个Promise对象
            // return new Promise((resolve, reject) => {
            //     // resolve('OK');
            //     reject('Error');
            // });
            //3. 抛出异常
            throw "Oh NO";
        }

        let result = main();

        console.log(result);
    </script>

await

  1. await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
  2. 如果表达式是 promise 对象, await 返回的是 promise 成功的值
  3. 如果表达式是其它值, 直接将此值作为 await 的返回值
    <script>
        async function main(){
            let p = new Promise((resolve, reject) => {
                // resolve('OK');
                reject('Error');
            })
            //1. 右侧为promise的情况
            // let res = await p;
            //2. 右侧为其他类型的数据
            // let res2 = await 20;
            //3. 如果promise是失败的状态
            try{
                let res3 = await p;
            }catch(e){
                console.log(e);
            }
        }

        main();
    </script>

async 和 await结合

/**
 * resource  1.html  2.html 3.html 文件内容
 */

const fs = require('fs');
const util = require('util');
const mineReadFile = util.promisify(fs.readFile);

//回调函数的方式
// fs.readFile('./resource/1.html', (err, data1) => {
//     if(err) throw err;
//     fs.readFile('./resource/2.html', (err, data2) => {
//         if(err) throw err;
//         fs.readFile('./resource/3.html', (err, data3) => {
//             if(err) throw err;
//             console.log(data1 + data2 + data3);
//         });
//     });
// });

//async 与 await
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.code);
    }
}

main();
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>async与await结合发送AJAX</title>
</head>
<body>
    <button id="btn">点击获取段子</button>
    <script>
        //axios
        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);
                        }
                    }
                }
            });
        }

        //段子接口地址 https://api.apiopen.top/getJoke
        let btn = document.querySelector('#btn');

        btn.addEventListener('click',async function(){
            //获取段子信息
            let duanzi = await sendAJAX('https://api.apiopen.top/getJoke');
            console.log(duanzi);
        });
    </script>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值