promise系列(一)
1.同步回调和异步回调
<script> // 同步回调 let arr = [1,2,3,4,5]; //对数组的每一个元素 * 10 返回新数组 forEach filter some every let newArr = arr.map(item => { // console.log(0); return item * 10; }); // 异步回调 promise 回调 $.get(url, data, callback) fs模块 readFile readdir setTimeout(() => { console.log(0); }, 1000); console.log(1); </script>
2.错误类型
<script> /** * 1. Error: 所有错误的父类型 2. ReferenceError: 引用的变量不存在 3. TypeError: 数据类型不正确的错误 4. RangeError: 数据值不在其所允许的范围内 5. SyntaxError: 语法错误 */ // ReferenceError 引用错误 // console.log(abc); // TypeError 类型错误 // let obj = {}; // obj(); // RangeError 范围 // let arr = new Array(-1);//长度 // console.log(arr); // SyntaxError 语法错误 // abcxxx(xxxxa'*9s); </script>
3.try...catch 处理错误
<script> /** * 语法固定 try...catch try 尝试的意思 catch 捕获 * 1. try catch捕获到错误之后, 后续代码可以继续执行 * 2. catch 可以将错误信息捕获到. e 是一个对象, 有message和stack两个属性 * 3. 抛出错误之后, 在后续的 try 里面的代码不会执行 * 4. try 不能捕获语法错误. 其他三种类型错误可以捕获. * 5. 允许使用 throw 手动的抛出错误 * 6. 抛出任意类型的数据 */ try { // console.log(a;//不能捕获到语法错误 let a = 100; let b = 0; if(b === 0) { //手动抛出错误对象 // throw new Error('除数不能为 0'); throw "除数不能为 0 "; } let result = a / b; console.log("lalala"); } catch (e) { console.log(e); console.log(e.message); console.log(e.stack); //处理错误的方式 //1. 写入日志文件 //2. 错误提醒 } console.log('ok'); </script>
同步代码和异步代码处理错误
<script> // 同步代码抛出错误 => 可以捕获 // function fn() { // console.log(a); // } // try { // fn(); //非手动捕获 // } catch (e) { // console.log(e.message); // } // 异步代码抛出错误 => 不能这样捕获 // function fn() { // setTimeout(() => { // console.log(a); // }, 1000) // } // try { // fn(); // } catch (e) { // console.log(e.message); // } // console.log('test'); //异步代码捕获错误的方式 // function fn() { // setTimeout(() => { // try { // console.log(a); // } catch (e) { // console.log(e.message); // } // }, 1000) // } // fn(); </script>
Promise基础使用
<script> // 2s后 随机生成一个数字 // 如果是偶数则成功(弹框数字,中奖啦), // 如果是奇数失败(控制台输出数字) // setTimeout(() => { // //获取时间戳 // let n = Date.now(); // // // if(n % 2=== 0){ // //成功 值 // alert(n + '中奖啦! 中奖啦! 笔记本和台式机有戏啦!!'); // }else{ // //失败 值 // console.log(n, "下次再接再厉!!"); // } // }, 2000); //Promise 实现 // let a = new Person("xiaohigh"); //成功和失败的值, p 对象出了有状态属性(status), 还有一个值的属性(value) let p = new Promise(function(resolve, reject){ //定时器 setTimeout(() => { let n = Date.now(); if(n % 2 === 0){ //成功 resolve(n); }else{ //失败 reject(n); } }, 2000) }); // 形参的潜规则名称 value 与 reason p.then(function(value){ alert("中奖啦!! oh year"+n); }, function(reason){ console.log("再接再厉"+n); }); </script>
2
//读取一个文件内容 ./resource/1.html const fs = require("fs"); // fs.readFile("./resource/1.html", (err, data) => { // if(err){ // console.log(err); // return; // } // console.log(data.toString()); // }); //Promise 的方式 let p = new Promise((resolve, reject) => { fs.readFile("./resource/1-33.html", (err, data) => { //判断是否出现错误 if(err) reject(err); resolve(data); }); }); //then 方法处理成功或失败的值 p.then((value) =>{ console.log(value.toString()); }, (reason)=>{ console.error(reason.code); });
3
//读取 1.html 和 2.html 合并输出到控制台 const fs = require("fs"); //回调函数的形式处理,回调地狱,特点,外层的函数的结果是内层函数的条件 // 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); // }) // }); // }); //Promise 形式 let p = new Promise((resolve, reject) => { //读取 1.html 文件内容 fs.readFile("./resource/1.html", (err, data) => { if (err) reject(err); resolve(data); }); }); //第二个文件读取 value 为 1.html 的文件内容 //p2为返回的新的promise实例化对象 let p2 = p.then(value => { //value为1.html的内容,//value是buffer类型数据 //返回一个 新的Promise 对象 return new Promise((resolve, reject) => { fs.readFile("./resource/2.html", (err, data) => { if(err) reject(err); resolve(value + data); }); }); }, reason => { }); //读取 3.html 的文件内容 let p3 = p2.then(value => { //value 为p2中正确状态的值,1.html和2.html的数据 //value是字符串类型数据,buffer类型相加是字符串类型 return new Promise((resolve, reject)=>{ fs.readFile("./resource/3.html", (err, data)=>{ if(err) reject(err); resolve(value + data); }); }) }, reason => { }); p3.then(value => { //value 为p3中正确状态的值,1.html和2.html和3.html的数据 console.log(value); //value是字符串类型数据 },reason => { })
4
//读取 1.html 和 2.html 3.html 合并输出到控制台 const fs = require("fs"); //Promise 形式 let p1 = new Promise((resolve, reject) => { //读取 1.html 文件内容 fs.readFile("./resource/1.html", (err, data) => { if (err) reject(err); resolve(data.toString()); }); }); let p2 = new Promise((resolve, reject)=>{ //读取 2.html 文件内容 fs.readFile("./resource/2.html", (err, data) => { if (err) reject(err); // console.log('dg') //失败的promise,还是会向下执行代码 resolve(data.toString()); }); }); let p3 = new Promise((resolve, reject)=>{ //读取 3.html 文件内容 fs.readFile("./resource/3.html", (err, data) => { if (err) reject(err); resolve(data.toString()); }); }); //只要有一个状态是失败的,p就是失败的promise let p = Promise.all([p1, p2, p3]); p.then(value => { // console.log(value) //value此时是数组,是偏p1,p2,p3的值得累加 // join()方法将一个数组(或一个类数组对象)的所有元素根据传入的参数连接成一个字符串,并返回这个字符串。 // 参数: // 指定一个字符串来分割数组(类数组)的每个元素 // 如果省略(),数组元素默认以逗号分隔。默认为"," // 如果为(""),则表示所有元素之间不存在任何字符 console.log(value.join('')); },reason=>{ console.log(reason) });
5.promise封装ajax请求
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Promise封装AJAX请求</title> <script crossorigin="anonymous" src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> </head> <body> <button id="btn">点击发送 AJAX 请求</button> <script> // $.get('/server', {}, function(){ // }) /* 封装一个函数 promiseAJAX 只实现 GET 请求 用来发送 AJAX 请求 返回 Promise 对象 */ //method = "GET", 函数默认参数,promiseAJAX()就是promise对象 function promiseAJAX({ url,data={name:'maco'}, method = "GET" }) { //对象解构 // console.log(url) // console.log(method) // console.log(data) //返回promise实例对象 return new Promise((resolve, reject) => { // 创建ajax实例对象 let x = new XMLHttpRequest(); //初始化 x.open(method, url); //发送 x.send(); //绑定事件, 处理响应结果 //只有ajax的状态改变了,才会触发该事件onreadystatechange x.onreadystatechange = function () {// 1->2 2->3 3-> 4 //只有状态为 4 的时候, 才能对 Promise 对象状态进行设置 if (x.readyState === 4) { //请求成功 2xx 都标识成功 3 重定向 4 客户端错误 5 服务端错误 if (x.status >= 200 && x.status < 300) { //成功的话, 将promise对象的状态设置为成功, 并将响应体设置为 promise 对象成功的值 resolve(x.response); } else { //失败的话 reject(x.status); } } } }); } btn.onclick = function () { //原生ajax-cors跨域,服务器的响应头设置了可跨域 let url = 'https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P'; promiseAJAX({ url: url }).then(value => { // 将字符窜转换成对象 let data=JSON.parse(value) console.log(data); }); } </script> </body> </html>
6.异步API的promsie形态
/* 封装一个函数 mineReadFile , 读取文件并返回一个 promise 对象 */ const fs = require("fs"); function mineReadFile(path) { //返回promise对象 return new Promise((resolve, reject)=>{ //使用 fs 模块读取文件内容 fs.readFile(path, (err, data) => { //如果失败 则修改promise对象状态为失败 if(err) reject(err); // 如果成功, 则修改promise对象状态为成功 resolve(data); }) }); } mineReadFile('./resource/xxx.html').then(value => { console.log(value.toString()); }, reason => { console.log(reason.code); });
7.promise的API
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Promise的API</title> </head> <body> <script> // function Promise(executor){ // } /** * 1. Promise 的实例化接收一个 函数类型的参数( 执行器函数 ) * 2. resolve和 reject 两个形参类型都是 函数. * 3. 执行器函数是一个同步的回调函数 */ // 1. 执行器函数式同步调用的,但是里头的异步任务是不同步的 // let p =new Promise((resolve, reject) => { // //同步调用 // console.log(111); // //异步调用 // setTimeout(()=>{ // console.log(333); // // reject("失败的数据"); // }, 1000); // }); // console.log(222); // 执行顺序, 输出,111, 222, 333 // 2. Promise.prototype.then //成功的回调 onResolved on 当...时候 resolved 已解决 //失败的回调 onRejected rejected 拒绝了的 失败了 // then方法返回的是一个promise对象,后面还可以加. // p.then(value=>{ // }, reason=>{ // }).then(value=>{ // }).then(value=> { // }); // 3. Promise.prototype.catch 实例对象上可以使用 catch 方法 // p.catch(reason => { // console.error(reason); // }); // 4. Promise.resolve resolve 是一个方法, 返回是一个 Promise 对象 // 4-1 参数如果为非 Promise 类型的数据, 则返回的 Promise 对象为成功的状态 // let p10=Promise.resolve('hrllow') // console.log(p10) //Promise { 'hrllow' } // p10.then((value)=>{ // console.log(value) //hrllow // }) // 4-2 参数如果是成功的 Promise, 则返回的 Promise 对象结果状态也为成功, // 并且返回的成功的promise的值, 为传入参数的成功的值 // let p1 = new Promise((resolve, reject)=>{ // resolve('成功的数据'); // }); // let p3 = Promise.resolve(p1); //Promise { '成功的数据' } // p3.then(value=>{ // console.log(value) //成功的数据 // }) // 4-3 如果参数为失败的 Promise, 则返回的是失败的 Promise 对象 // 返回的值,报错 let p11 = new Promise((resolve, reject) => { reject("失败的数据111"); }); let p4 = Promise.resolve(p11); console.log(p4); //Promise { <rejected> '失败的数据111' } // p4.then(value=>{ // console.log(value) // Uncaught (in promise) 失败的数据111 // }) p4.catch(reason=>{ console.log(reason) //失败的数据111 }) // 5-1. Promise.reject 参数为成功的promise对象,返回失败的 Promise 对象, 返回的值是一个失败原因的对象 // let p0 = new Promise((resolve, reject)=>{ // resolve('成功的数据'); // }); // let p2 = Promise.reject(p0); // console.log(p2); //Promise {<rejected>: Promise} // p2.catch( reason=>{ // console.log(reason) //Promise {<resolved>: "成功的数据"} // }) // 5-2. Promise.reject 参数为失败的promise对象,返回失败的 Promise 对象, 返回的值是一个失败原因的对象 // let p20 = new Promise((resolve, reject)=>{ // reject('成功的数据'); // }); // let p21 = Promise.reject(p20); // console.log(p21); //Promise {<rejected>: Promise} // p21.catch( reason=>{ // console.log(reason) //Promise {<rejected>: "成功的数据"} // }) //5-3,Promise.reject 参数为非promise数据,返回失败的 Promise 对象, 返回的值为失败的值 // let p6=Promise.reject('ABN') // console.log(p6) //Promise {<rejected>: "ABN"} // p6.catch(reason=>{ // console.log(reason) //ABN // }) // 6. Promise.all, // let one = new Promise((resolve, reject) => { // // reject('数据库用户的数据'); // // resolve('数据库用户的数据'); // }); // let two = Promise.resolve("订单数据"); // let three = Promise.resolve("商品数据"); // Promise.all函数的数组参数的promise如果都是成功的状态,那么p1也是成功的promise,而他的返回值是数组 // 如果有一个参数是失败的promise,那么p1就是失败的promise, // let p1 = Promise.all([one, two, three]); // console.log(p1) //Promise {resolved} // p1.then(value=>{ // console.log(value) //[ '数据库用户的数据', '订单数据', '商品数据' ] // }) // 7. Promise.race race 赛跑的意思, let one = new Promise((resolve, reject) => { reject('数据库用户的数据'); //异步调用 // setTimeout(() => { // reject('数据库用户的数据'); // }, 1000); }); let two = Promise.reject("订单数据"); // let two = Promise.resolve("订单数据"); let three = Promise.resolve("商品数据"); //Promise.race函数的数组里头的参数,p1的状态初始是pending默认状态,那个promise状态第一个先改变,p1的状态就会跟着改变 // 返回的值就是那个引起变化的promise的值,偏 let p1 = Promise.race([one, two, three]); console.log(p1); p1.then(value=>{ console.log(value) },reason=>{ console.log(reason) }) </script> </body> </html>
8.如何改变promsie的状态
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>关键问题</title> </head> <body> <script> let p = new Promise((resolve, reject) => { //1. resolve //"pending"状态的promise // resolve('数据'); //resolved //2. reject // reject('错误'); //rejected" //3. 抛出错误,会改变promise的状态 // throw new Error("出错啦!!"); //rejected" // throw "出错啦!!"; //"rejected" //4. 异步回调 异步回调中抛出错误 不能改变 promise 对象状态 // 但是里头加入try,catch即可捕获到错误,就能改变promise的状态 //异步任务 // setTimeout(()=>{ // reject('失败') //rejected // },1000) // setTimeout(()=>{ // throw '出错了' // "pending,未改变状态 // },1000) setTimeout(()=>{ try{ throw '出错了' ; }catch(e){ reject(e) //"rejected } },1000) }) console.log(p); </script> </body> </html>
9、改变状态和与指定回调谁先谁后
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>关键问题</title> </head> <body> <script> // 改变promise状态和指定回调函数谁先谁后? // 1.如果promise中有异步任务,那么先调用then()指定里头的回调,然后在改变promise状态, // 然后返回改变状态的值。这种居多,因为promise里头就是封装异步任务的。 // 2.如果promise中有没有异步任务,那么先改变promise状态,然后调用then()指定里头的回调, // 然后返回改变状态的值 //3.then()方法里头的回调函数也是异步任务 let p = new Promise((resolve, reject) => { //异步任务 // setTimeout(() => { // console.log(111); // resolve("OK"); // }, 2000); //同步任务 console.log(111); resolve("OK"); }); console.log(222); p.then(value => { console.log(value); }) console.log(333) </script> </body> </html>
10.then 方法返回结果特点
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>关键问题</title> </head> <body> <script> let p = new Promise((resolve, reject)=>{ // resolve('成功') reject('失败'); }); //由then()指定的回调函数执行的结果决定 let result = p.then(value => { //1. 抛出错误 ,返回的就是reject状态的promise // throw "错误!!"; //"rejected"状态的promise //2. 返回非 Promise 类型的对象,如果没有return结果,也是resolved状态 // return 123; //"resolved状态的promise, //3. 返回 Promise 类型的对象 return new Promise((resolve, reject)=>{ // 成功的情况 // resolve("OK"); //resolved状态的promise,值就是result的值 // 失败的情况 reject('Error'); //rejected状态的promise }); }, reason => { console.log(reason) //失败 return 444 //resolved状态的promise,值就是444,没有return结果,也是resolved状态的promise }); console.log(result); </script> </body> </html>
11.then方法链式调用
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>关键问题</title> </head> <body> <script> let p = new Promise((resolve, reject)=>{ // resolve('000'); reject('出错') }); let p2= p.then(value => { console.log(value); //000 return 111; //返回状态为resolve,值为111的promise },reason => { console.error(reason); //出错 return 222; ////返回状态为resolve,值为222的promise }) .then(value => { console.log(value); //111 /222 return 333; //返回状态为resolve,值为333的promise },reason=>{ console.error(reason) }) .then(value => { console.log(value); //333 return 444; //返回状态为resolve,值444的promise }); console.log(p2) //Promise {<resolve>},值为444 </script> </body> </html>
12.异常穿透
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>关键问题</title> </head> <body> <script> // 如果出现了状态为rejcet的promise,调用then方法,如果没有写明第二个回调函数,会忽略, // 直到遇到catch(),才会执行。异常穿透 let p = new Promise((resolve, reject) => { resolve('000'); // reject('失败ooo'); }); p.then(value => { console.log(value); throw "Error"; }).then(value => { console.log(value); return 333; }).then(value => { console.log(value); return 444; }).then(value=> { console.log(value); }).catch(reason => { console.log(reason); }); </script> </body> </html>
13.中断promise链
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>关键问题</title> </head> <body> <script> // 如何当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数 // 办法: 在回调函数中返回一个pendding状态的promise对象 let p = new Promise((resolve, reject) => { resolve('000'); // reject('失败ooo'); }); p.then(value => { console.log(value); return 111; }).then(value => { console.log(value); return 222; }).then(value => { console.log(value); // 在回调函数中返回一个pendding状态的promise对象 return new Promise((resolve, reject)=>{}); }).then(value => { console.log(value); }).catch(reason => { console.log(reason); }); </script> </body> </html>