Promise JavaScript 中存在很多异步操作,Promise 将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。可以通过链式调用多个 Promise 达到我们的目的。
Promise 在各种开源库中已经实现,现在标准化后被浏览器默认支持。
promise 是一个拥有 then 方法的对象或函数
 
问题探讨 下面通过多个示例来感受一下不使用 promise 时,处理相应问题的不易,及生成了不便阅读的代码。
定时嵌套 下面是一个定时器执行结束后,执行另一个定时器,这种嵌套造成代码不易阅读
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38  <style>       div {         position: absolute;         width: 100px;         height: 100px;         background-color: pink;       } </style> <body>     <div></div> </body> <script>       function createInterval(callback, delay = 50) {         let timer = setInterval(() => {           callback(timer);         }, delay);       }       const div = document.querySelector("div");       console.log(parseFloat(window.getComputedStyle(div).left));       function run() {         createInterval((timer) => {           div.style.left =             parseFloat(window.getComputedStyle(div).left) + 2 + "px";           // console.log("left");           if (parseFloat(div.style.left) >= 50) {             clearInterval(timer);             createInterval((timer) => {               div.style.width =                 parseFloat(window.getComputedStyle(div).width) - 2 + "px";               // console.log("width");               parseFloat(div.style.width) <= 0 && clearInterval(timer);             });           }         });       }       div.addEventListener("click", run); </script> 
 
图片加载 下面是图片后设置图片边框,也需要使用回调函数处理,代码嵌套较复杂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function createImage(file, resolve, reject) {   const img = new Image();   img.src = file;   img.onload = () => {     resolve(img);     console.log("image Loading fulfilled");   };   img.onerror = () => {     console.log("image loading fail");   };   document.body.append(img); } createImage("./images/img1.jpg", (img) => {   img.style.border = "5px solid pink"; }); 
 
加载文件 下面是异步加载外部JS文件,需要使用回调函数执行,并设置的错误处理的回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function loadJS(file, resolve, reject) {   let script = document.createElement("script");   script.src = file;   script.onload = resolve;   script.onerror = reject;   document.body.append(script); } loadJS(   "./js/ashun.js",   (script) => {     console.log(`${script.path[0].src}  load Resolve`);     title();   },   (err) => console.log(`${err.srcElement.src}  load Reject`) ); 
 
实例中用到的 ashun.js 与 SHUN.js 内容如下
1 2 3 4 5 6 7 8 9 10 # ashun.js function title() {   console.log("title method"); } # SHUN.js function run() {   title();   console.log("run method"); } 
 
如果要加载多个脚本时需要嵌套使用,下面SHUN.js 依赖 ashun.js,需要先加载ashun.js 后加载SHUN.js
不断的回调函数操作将产生回调地狱,使代码很难维护
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function loadJS(file,resolve,reject){……}    loadJS(         "/js/ashun.js",         (script) => {           loadJS(             "/js/SHUN.js",             (script) => {               run();               console.log(`${script.path[0].src}  load Resolve`);             },             (err) => {               console.log(`${err.srcElement.src}加载失败`);             }           );           console.log(`${script.path[0].src}  load Resolve`);         },         (err) => {           console.log(`${err.srcElement.src}加载失败`);         }     ); 
 
异步请求 使用传统的异步请求也会产生回调嵌套的问题。
比如若要获取商品的详情,就要分为两步
先请求商品数据,得到商品的id 
根据商品id请求获取对应商品的详情数据。 
 
以下接口无实际用途,仅作示例,可自己编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function ajax(url, resolve, reject) {   let xhr = new XMLHttpRequest();   xhr.open("GET", url);   xhr.send();   xhr.onload = function() {     if (this.status == 200) {       resolve(JSON.parse(this.response));     } else {       reject(this);     }   }; } ajax("http://localhost:8888/goodslist/data, goods => {   ajax(     `http://localhost:8888/category?id=${goods["id"]}`,     response => {       console.log(response[0]);     }   ); }); 
 
肯德基 下面是模拟肯德基吃饭的事情,使用 promise 操作异步的方式每个阶段会很清楚
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 let kfc = new Promise((resolve, reject) => {   console.log("肯德基正在为您做餐……");   setTimeout(() => {     resolve("餐品已经做好,为您上桌");   }, 2000); }); let as = kfc.then((result) => {   console.log(result);   console.log("阿顺收到消息");   return {     then(resolve, reject) {       setTimeout(() => {         resolve("我吃了2秒,不辣,张三你可以吃了");       }, 2000);     },   }; }); let zhangsan = as.then((msg) => {   return new Promise((resolve, reject) => {     console.log("张三收到阿顺消息:" + msg);     setTimeout(() => {       let msg = "我吃了1秒,真好吃, 李四也尝尝吧";       console.log(msg);       resolve(msg);     }, 1000);   }); }); let lisi = zhangsan.then((result) => {   console.log("李四收到消息:" + result);   setTimeout(() => {     console.log("李四:我吃了1秒,不错不错");   }, 1000); }); 
 
而使用以往的回调方式,就会让人苦不堪言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function notice(msg, then) {   then(msg); } function meal() {   notice("肯德基厨房开始做饭", (msg) => {     console.log(msg);     notice("我是肯德基,你的餐已经做好", (msg) => {       console.log(`阿顺收到肯德基消息: ${msg}`);       setTimeout(() => {         notice("张三,我吃了两秒了,不辣,你可以吃了", (msg) => {           console.log(`张三收到阿顺消息: ${msg}`);           setTimeout(() => {             notice("很好吃,李四也尝尝吧", (msg) => {               console.log(msg);               notice("李四收到消息", (msg) => {                 console.log(msg);                 setTimeout(() => {                   console.log("李四:不错不错");                 }, 1000);               });             });           }, 2000);         });       }, 2000);     });   }); } meal(); 
 
 
异步状态 Promise 意为承诺,就像我们去饭店用餐,点完餐后服务员会给我们一个票号,如果饭菜做好,我们凭借票号去领餐,这就代表成功状态,若由于其它原因饭菜不能够顺利做好,这就代表拒绝状态。在得到这些结果前,我们一直处于等待的状态。
一个 promise 必须有一个 then 方法用于处理状态改变 
 
状态说明 Promise包含pending、fulfilled、rejected三种状态
pending 指等待状态,初始化 promise 时的状态 
resolve 指已经解决,将 promise 状态设置为fulfilled 
reject 指拒绝处理,将 promise 状态设置为rejected 
promise 是生产者,通过 resolve 与 reject 函数告知结果 
promise 非常适合需要一定执行时间的异步任务 
同一Promise状态一旦确定(fufilled\rejected),状态将不可再次更改 
 
promise 是队列状态,就像体育中的接力赛,或多米诺骨牌游戏,状态一直向后传递,当然 也可更改其中的任何一个promise的状态,来影响后续的promise。
promise 没有使用 resolve 或 reject 更改状态时,默认状态为 pending
1 2 3 4 console.log(   new Promise((resolve, reject) => {   }); ); //Promise {<pending>} 
 
当更改状态后
1 2 3 4 5 6 7 8 9 10 11 console.log(   new Promise((resolve, reject) => {     resolve("fulfilled");   }) ); //Promise {<resolved>: "fulfilled"} console.log(   new Promise((resolve, reject) => {     reject("rejected");   }) ); //Promise {<rejected>: "rejected"} //Error 
 
若一个Promise为rejected状态,却没有处理,系统会发出警示。
1 2 3 4 5 console.log(   new Promise((resolve, reject) => {     reject("rejected");   }) ); //Promise {<rejected>: "rejected"} //Error:Uncaught (in promise) rejected 
 
使用then\catch处理后,不会报错,then\catch这些方法默认也会返回一个新的promise
1 2 3 4 5 console.log(         new Promise((resolve, reject) => {           reject("rejected");         }).catch((err) => {}) ); //Promise {<pending>} 
 
按理来说上述Promise已经确认为rejected状态,也经过了then\catch的onRejected回调函数处理,应该返回fufilled状态(then\catch默认返回的promise状态为fufilled),但是为什么返回pending状态呢?
console.log是同步代码会立即执行,当日志信息被打印时,promise的状态还未被确认,所以返回pending 
将打印放在宏任务队列中,可看到正确结果 
 
关于任务队列,下一章节会详细讲解
1 2 3 4 5 6 7 8 9 10 let promise = new Promise((resolve, reject) => {   reject("rejected"); }); let p1 = promise.catch((err) => err); console.log(promise)//Promise {<rejected>:"rejected"} console.log(p1);		//Promise {<pending>} setTimeout(() => {   console.log(p1);	//Promise {<fulfilled>:"rejected"} });   
 
promise 自创建时,立即执行同步任务,then 会放在异步微任务中执行,需要等同步任务执行后才执行。
1 2 3 4 5 6 7 8 9 let promise = new Promise((resolve, reject) => {   resolve("fulfilled");   console.log("阿顺"); }); promise.then(msg => {   console.log(msg); }); console.log("阿顺特烦恼"); // 阿顺 阿顺特烦恼 fulfilled 
 
1 2 3 4 5 6 const promise = new Promise((resolve) => { 	resolve("fulfilled"); }); promise.then(alert); alert("阿顺特烦恼"); promise.then((_) => alert("ashuntefannao")); 
 
下例在三秒后将 Promise 状态设置为 fulfilled ,然后执行 then 方法
1 2 3 4 5 6 7 8 9 10 11 12 new Promise((resolve, reject) => {   setTimeout(() => {     resolve("fulfilled");   }, 3000); }).then(   msg => {     console.log(msg);   },   error => {     console.log(error);   } ); 
 
状态被改变后就不能再修改了,下面先通过resolve 改变为成功状态,表示promise 状态已经完成,就不能使用 reject 更改状态了
1 2 3 4 5 6 7 8 9 10 11 new Promise((resolve, reject) => {   resolve("操作成功");   reject(new Error("请求失败")); }).then(   msg => {     console.log(msg);   },   error => {     console.log(error);   } ); 
 
动态改变 可以在一个promise中,通过处理另一个promise1,来改变promise的状态。
当在一个promise中,告知状态时传入的是另一个promise1,则后续使用then或其它方法对其进行处理时,处理的已经不再是promise的状态,而是promise1。
在p2中确认resolve状态,但在后续的then中却执行了rejected回调函数。 
在p2中确认状态时,返回的是p1,那么后续处理的promise将是p1,p2的状态已经无意义 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 {       let p1 = new Promise((resolve, reject) => {         reject("p1 reject");       });              let p2 = new Promise((resolve, reject) => {         console.log(`p2发送resolve状态`);         resolve(p1);       }).then(         (result) => console.log(`p2 处理结果:fulfilled--${result}`),         (err) => console.log(`p2 处理结果:rejected--${err}`)       ); } 
 
 
then 一个promise 需要提供一个then方法访问promise 结果,then 用于当 promise 状态发生改变时的处理,即promise处理异步操作过程,then 用于处理结果。
promise 就像 饭馆 中的厨房,then 就是我们用户,如果餐做好了即 fulfilled ,做不了拒绝即rejected 状态。那么 then 就要对不同状态处理。
then 方法 必须  返回 promise,用户返回或系统自动返回 
第一个函数在resolved 状态时执行,即使用resolve确认完成状态时,执行then第一个callback处理成功状态 
第二个函数在rejected状态时执行,即使用reject确认拒绝状态时,执行第二个callback处理失败状态,该函数是可选的 
两个callback都接收 promise 确认状态时传入的值做为参数 
也可以使用catch 来处理失败的状态 
如果在 then 中手动返回 promise ,下一个then 会在上一个then返回的promise 状态改变后执行 
 
语法说明 then的语法如下,onFulfilled 函数处理 fulfilled 状态, onRejected函数处理 rejected 状态
onFulfilled 或 onRejected 不是函数将被忽略 
两个函数只会被调用一次 
onFulfilled 在 promise 执行成功时调用 
onRejected 在 promise 执行拒绝时调用 
 
1 promise.then(onFulfilled, onRejected) 
 
 
基础知识 then 会在 promise 确认状态后执行,then 第一个callback在 resolve成功状态执行
1 2 3 4 5 6 7 8 9 10 const promise = new Promise((resolve, reject) => {   resolve("success"); }).then(   value => {     console.log(`解决:${value}`);   },   reason => {     console.log(`拒绝:${reason}`);   } ); 
 
then 中第二个参数在失败状态执行
1 2 3 4 5 6 7 8 9 10 11 const promise = new Promise((resolve, reject) => {   reject("is error"); }); promise.then(   msg => {     console.log(`成功:${msg}`);   },   error => {     console.log(`失败:${error}`);   } ); 
 
如果只关心成功则不需要传递 then 的第二个参数
1 2 3 4 5 6 const promise = new Promise((resolve, reject) => {   resolve("success"); }); promise.then(msg => {   console.log(`成功:${msg}`); }); 
 
如果只关心失败时状态,then 的第一个参数传递 null
1 2 3 4 5 6 const promise = new Promise((resolve, reject) => {   reject("is error"); }); promise.then(null, error => {   console.log(`失败:${error}`); }); 
 
promise 确认状态后转入的参数,会传入到then对应callback的参数中,如果then没有可处理函数,会一直向后传递
1 2 3 4 5 6 7 8 let p1 = new Promise((resolve, reject) => { 	reject("rejected"); }) .then() .then(   null,   f => console.log(f) ); 
 
1 2 3 4 5 6 7 let promise = new Promise((resolve, reject) => {   resolve("resolve"); }); let p2 = promise.then(); p2.then().then(resolve => {   console.log(resolve); }); 
 
1 2 3 4 5 6 7 let promise = new Promise((resolve, reject) => {   reject("reject"); }); let p2 = promise.then(() => {}); p2.then(null, null).then(null, reject => {   console.log(reject); }); 
 
链式调用 
then\catch等promise的方法,是对上一个promise状态的处理,而使用then/catch后 它们本身又会默认返回一个新的promise,且状态为fulfilled,所以then才可不断地链式调用。 
当然,也可以在then\catch中手动返回自定义的promise,可通过这个promise,改变当前then的状态 
 
每次的 then 都是一个全新的 promise, then 默认返回的 promise 状态是 fulfilled
1 2 3 4 5 6 7 8 {      let promise = new Promise((resolve, reject) => {        reject("promise state rejected");      });      promise        .then(null, (err) => console.log(err))        .then((_) => console.log("then默认状态为fulfilled")); } 
 
每次的 then 都是一个全新的 promise,不要认为上一个 promise状态会影响以后then返回的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let p1 = new Promise(resolve => {   rejected("p1 rejected"); }); let p2 = p1.then(null,rej=>console.log(reg)); p2.then(() => {   console.log("Ashuntefannao"); }); console.log(p1); // Promise {<resolved>} console.log(p2); // Promise {<pending>} setTimeout(() => {   console.log(p1); // Promise {<resolved>}   console.log(p2); // Promise {<resolved>} }); 
 
then 是对上个promise 的处理,每个 then 又会返回一个promise,默认传递 fulfilled状态,所以才可以不断地链式调用then处理promise。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 new Promise((resolve, reject) => {   reject(); }) .then(   resolve => console.log("fulfilled"),   reject => console.log("rejected") ) .then(   resolve => console.log("fulfilled"),   reject => console.log("rejected") ) .then(   resolve => console.log("fulfilled"),   reject => console.log("rejected") );    # 执行结果如下   rejected   fulfilled   fulfilled 
 
如果内部手动返回 promise 时,后续处理的便是该 promise,即该promise可以改变当前then的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 {        let promise = new Promise((resolve, reject) => {          reject("promise state rejected");        });        promise          .then(            (result) => console.log("fulfilled"),            (reject) => console.log(reject)          )          .then(            (res) => console.log("fufilled"),            (rej) => console.log("rejected")          )          .then((res) => {            console.log("fufilled");            return Promise.reject("手动返回的promise,状态为rejected");          })          .then(            (res) => console.log("fufilled"),            (rej) => console.log(rej)          ); } # 执行结果如下  "promise state rejected"  "fulfilled"  "fulfilled"  "手动返回的promise,状态为rejected" 
 
若手动返回的不是Promise,则下一个then处理的还是 上一个then默认返回的Promise,状态为fulfilled。
但是下一个then对应的处理函数,会接受上一个then返回的参数。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {         let promise = new Promise((resolve, reject) => {           reject("promise state rejected");         });         let p1 = promise.then(null, (rej) => {         	console.log(rej)           return "p1 rejected";         });         let p2 = p1.then((res) => {           console.log(`p2 fulfilled \n${res}`);         }); }  # 执行结果如下   "promise state rejected"   "p2 fulfilled    p1 rejected" 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 new Promise((resolve, reject) => {   resolve(); }) .then(v => {   return new Promise((resolve, reject) => {     resolve("第二个promise");   }); }) .then(value => {   console.log(value);   return value; }) .then(value => {   console.log(value); }); 
 
then是处理上一个Promise的结果,只有上一个promise确认了状态,then才会执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {         let promise = new Promise((resolve, reject) => {           setTimeout(() => {             resolve("promise fulfilled");           }, 1000);         })           .then((res) => {             console.log(res);             return new Promise((resolve) => {               setTimeout(() => {                 resolve("resolved");               }, 1000);             });           })           .then((res) => console.log(res)); } 
 
循环调用 
如果 then 的返回值与所处理的 promise 相同将禁止执行,(避免陷入死循环)
1 2 3 4 5 6 let promise = new Promise(resolve => {   resolve(); }); let p2 = promise.then(() => {   return p2; }); // TypeError: Chaining cycle detected for promise 
 
 
其它类型 then able :具有then能力的类型
Promise 解决过程是一个抽象的操作,其需输入一个 promise 和一个值,我们表示为 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise 。
也就是说,如果x具有then方法,那么将会被系统认为是类promise的结构 
若在Promise中返回x,则使用then处理Promise时,系统会尝试让原Promise的then方法接收x中then方法的状态 
 
包含then方法的Object可以当作promise使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 {         let promise = new Promise((resolve, reject) => {           resolve({             then(resolve, reject) {               resolve("promise fulfilled");             },           });         });         let p1 = promise.then((result) => {           console.log(result);           return {             then(resolve, reject) {               setTimeout(() => {                 reject(" p1 rejected");               }, 1000);             },           };         });         p1.then(           (mgs) => {             console.log(mgs);           },           (rej) => console.log(rej)         ); } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Goods {   constructor(id) {     this.id = id;   }   then(resolve, reject) {     resolve(ajax(`http://localhost:8083/goods?id=${this.id}`));   } } new Promise((resolve, reject) => {   resolve(ajax(`http://localhost:8083/goodsList?type=new`)); }) .then(goods => {   return new Goods(goods.id); }) .then(category => {   console.log(category); }); 
 
当然也可以是类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 new Promise((resolve, reject) => {   resolve(     class {       static then(resolve, reject) {         setTimeout(() => {           resolve("解决状态");         }, 2000);       }     }   ); }).then(   v => {     console.log(`fulfilled: ${v}`);   },   v => {     console.log(`rejected: ${v}`);   } ); 
 
如果对象中的 then 不是函数,则将对象做为值传递
1 2 3 4 5 6 7 8 9 10 11 new Promise((resolve, reject) => {   resolve(); }) .then(() => {   return {     then: "阿顺特烦恼"   }; }) .then(v => {   console.log(v); //{then: "阿顺特烦恼"} }); 
 
 
catch 基础知识 下面使用未定义的变量同样会触发失败状态
1 2 3 4 5 6 let promise = new Promise((resolve, reject) => {   as; }).then(   value => console.log(value),   reason => console.log(reason) ); 
 
如果 onFulfilled 或 onRejected 抛出异常,则 p2 拒绝执行并返回拒因
1 2 3 4 5 6 7 let promise = new Promise((resolve, reject) => {   throw new Error("fail"); }); let p2 = promise.then(); p2.then().then(null, resolve => {   console.log(resolve + ",阿顺特烦恼"); }); 
 
catch(err=>{})是用来接收Promise拒绝状态的。经catch处理后,默认返回的promise状态也为fulfilled 
catch相当于then(null,onReject) 
若某个promise已被then(null,onReject)处理,则catch将不会接收该拒绝状态 
 
1 2 3 4 5 6 7 8 9 {         let promise = new Promise((resolve, reject) => {           reject("rejected");         });         let p1 = promise.catch((err) => console.log(err));         setTimeout(() => {           console.log(p1);         }); } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 {         let promise = new Promise((resolve, reject) => {           reject("promise rejected");         });         promise           .then(null, (resolve) => {             console.log(resolve + ",阿顺特烦恼");           })           .catch((err) => console.log(err)); } //	promise rejected,阿顺特烦恼 {         let promise = new Promise((resolve, reject) => {           reject("promise rejected");         });         promise           .catch((err) => console.log(err))           .then(null, (resolve) => {             console.log(resolve + ",阿顺特烦恼");           }); } //	promise rejected 
 
建议使用 catch 处理错误 
将 catch 放在最后面用于统一处理前面发生的错误 
 
1 2 3 4 5 const promise = new Promise((resolve, reject) => {   reject(new Error("Notice: Promise Exception")); }).catch(msg => {   console.error(msg); }); 
 
catch 可以捕获之前所有 promise 的错误,所以建议将 catch 放在最后。下例中 catch 也可以捕获到了第一个 then 返回 的 promise 的错误。
1 2 3 4 5 6 7 8 9 10 11 12 new Promise((resolve, reject) => {   resolve(); }) .then(() => {   return new Promise((resolve, reject) => {     reject("err from .then ");   }); }) .then(() => {}) .catch(msg => {   console.log(msg); }); 
 
错误是冒泡的操作的,下面没有任何一个then 定义第二个函数参数onRejected,将一直冒泡到 catch 处理错误
1 2 3 4 5 6 7 8 new Promise((resolve, reject) => {   reject(new Error("请求失败")); }) .then(msg => {}) .then(msg => {}) .catch(error => {   console.log(error); }); 
 
catch 也可以捕获对 then 抛出的错误处理
1 2 3 4 5 6 7 8 9 new Promise((resolve, reject) => {   resolve(); }) .then(msg => {   throw new Error("这是then 抛出的错误"); }) .catch(() => {   console.log("33"); }); 
 
catch 也可以捕获其他错误,下面在 then 中使用了未定义的变量,将会把错误抛出到 catch
1 2 3 4 5 6 7 8 9 new Promise((resolve, reject) => {   resolve("success"); }) .then(msg => {   console.log(a); }) .catch(reason => {   console.log(reason); }); 
 
 
处理机制 1 2 3 4 5 const promise = new Promise((resolve, reject) => {   throw new Error("fail"); }).catch(msg => {   console.log(msg.toString()+"阿顺特烦恼"); }); 
 
可以将上面的理解为如下代码,可以理解为内部自动执行 try...catch
1 2 3 4 5 6 7 8 9 const promise = new Promise((resolve, reject) => {   try {     throw new Error("fail");   } catch (error) {     reject(error);   } }).catch(msg => {   console.log(msg.toString()); }); 
 
但像下面的在异步宏任务中 throw new Error 将不会触发 catch,而使用系统错误处理
1 2 3 4 5 6 7 const promise = new Promise((resolve, reject) => {   setTimeout(() => {     throw new Error("fail");   }, 2000); }).catch(msg => {   console.log(msg + "阿顺特烦恼"); }); 
 
在 catch 中发生的错误也会抛给最近的错误处理
1 2 3 4 5 6 7 8 9 const promise = new Promise((resolve, reject) => {   reject(); }) .catch(msg => {   ashun(); }) .then(null, error => {   console.log(error); }); 
 
 
定制错误 可以根据不同的错误类型进行定制操作,下面将url格式错误与参数错误分别进行了处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class ParamError extends Error {   constructor(msg) {     super(msg);     this.name = "ParamError";   } } class HttpError extends Error {   constructor(msg) {     super(msg);     this.name = "HttpError";   } } function ajax(url) {   return new Promise((resolve, reject) => {     if (!/^http/.test(url)) {       throw new HttpError("请求地址格式错误");     }     let xhr = new XMLHttpRequest();     xhr.open("GET", url);     xhr.send();     xhr.onload = function() {       if (this.status == 200) {         resolve(JSON.parse(this.response));       } else if (this.status == 404) {         // throw new ParamError("用户不存在");         reject(new ParamError("用户不存在"));       } else {         reject("加载失败");       }     };     xhr.onerror = function() {       reject(this);     };   }); } ajax(`http://localhost:8083?name=阿顺特烦恼`) .then(value => {   console.log(value); }) .catch(error => {   if (error instanceof ParamError) {     console.log(`参数错误:${error.message}`);   }   if (error instanceof HttpError) {     alert(`url格式错误:${error.message}`);   }   console.log(error); }); 
 
 
finally 无论状态是resolve 或 reject 都会执行此动作,finally 与状态无关。
根据finally的特性,通常在其中做一些公共的操作,不论状态,都会执行的操作。 
 
1 2 3 4 5 6 7 8 9 10 11 12 const promise = new Promise((resolve, reject) => {   reject("阿顺特烦恼"); }) .then(msg => {   console.log("resolve"); }) .catch(msg => {   console.log("reject"); }) .finally(() => {   console.log("resolve/reject状态都会执行"); }); 
 
下面使用 finally 处理加载状态,当图片加载完成时移除加载图标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <style>       div {         position: absolute;         width: 100px;         height: 100px;         background-color: pink;       }       .result {         display: none;       } </style> <body>     <div class="loading">loading...</div>     <div class="result"></div> </body> <script>       function createImage(file) {         return new Promise((resolve, reject) => {           let img = new Image();           img.src = file;           img.onload = () => resolve(img);           img.onerror = () => reject("加载失败");         });       }       setTimeout(() => {         createImage("./images/img1.jpg")           .then((img) => {             document.body.append(img);             document.querySelector(".result").innerHTML = "加载成功";           })           .catch((err) => {             console.log(err);             document.querySelector(".result").innerHTML = err;           })           .finally(() => {             document.querySelector("div").style.display = "none";             document.querySelector(".result").style.display = "block";           });       }, 1000); </script> 
 
实例操作 异步请求 下面是将 ajax 请求使用 promise 处理,代码结构清晰了很多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function ajax(url) {   return new Promise((resolve, reject) => {     let xhr = new XMLHttpRequest();     xhr.open("GET", url);     xhr.send();     xhr.onload = function() {       if (this.status == 200) {         resolve(JSON.parse(this.response));       } else {         reject(this);       }     };   }); } ajax("http://localhost:8083/goodsList?name=new") .then(goods =>ajax(`http://localhost:8083/category?id=${goods["id"]}`)) .then(data => {   console.log(data); }); 
 
脚本加载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 {         function loadJS(file) {           return new Promise((resolve, reject) => {             let script = document.createElement("script");             script.src = file;             document.body.append(script);             script.onload = () => {               resolve(script);             };             script.onerror = () => {               reject(script);             };           });         }         loadJS("./js/ashun.js")           .then((script) => {             title();             console.log("ashun.js finishLaod");             return script;           })           .then((ashunjs) => {             return loadJS("./js/SHUN.js").then((script) => {               console.log("SHUN.js finishLaod");               run();             });           })           .catch((script) => console.log(`${script.src}:加载失败`)); } 
 
定时器 下面是封装的timeout 函数,使用定时器操作更加方便
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function timeout(times) {   return new Promise(resolve => {     setTimeout(resolve, times);   }); } timeout(3000)   .then(() => {     console.log("3秒后执行");     return timeout(1000);   })   .then(() => {     console.log("执行上一步的promise后1秒执行");   }); 
 
使用Promise封装 setInterval 定时器并实现动画效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <style>     div {       width: 100px;       height: 100px;       background: pink;       position: absolute;     } </style> <body>   <div></div> </body> <script>         function interval(callback, delay = 5) {           return new Promise((resolve, reject) => {             let id = setInterval(() => {               callback(id, resolve);             }, delay);           });         }         let div = document.querySelector("div");         function run() {           const step = 2;           interval((timer, resolve) => {             let left = parseFloat(window.getComputedStyle(div).left);             if (left >= 200) {               clearInterval(timer);               resolve("left end");             }             div.style.left = left + step + "px";           })             .then((result) => {               console.log(result);               return interval((timer, resolve) => {                 let width = parseFloat(window.getComputedStyle(div).width);                 if (width <= 0) {                   clearInterval(timer);                   resolve("width end");                 }                 div.style.width = width - step + "px";               });             })             .then((result) => console.log(result));         }                  div.addEventListener("click", run); </script> 
 
 
链式操作 
每个 then 都是一个promise,then会默认返回一个promise,且状态为fulfilled。 
如果在 then 中手动返回一个新promsie,只当这个新的promise 确认状态后,才会继承执行下一个 then 
 
语法介绍 下面是对同一个 promise 分别使用不同的 then 进行操作 ,每个then 都得到了同一个promise 结果,这不是链式操作,实际使用意义不大。
 
1 2 3 4 5 6 7 8 9 10 11 const promise = new Promise((resolve, reject) => {   resolve("阿顺特烦恼"); }); promise.then(title => {   title += "-Ashun";   console.log(title); //阿顺特烦恼-Ashun }); promise.then(title => {   title += "-Ashuntefannao";   console.log(title); //阿顺特烦恼-Ashuntefannao }); 
 
promise 中的 then 方法可以链式调用,then 方法的返回值会传递到下一个then 方法对应的处理函数中。
then 会返回一个promise ,所以如果有多个then 时会连续执行 
then 返回的值会做为当前promise 的结果 
 
下面是链式操作的 then,即始没有 return 也是会执行,因为每个then 默认会返回promise
1 2 3 4 5 6 7 8 9 10 11 12 new Promise((resolve, reject) => {   resolve("阿顺特烦恼"); })   .then((title) => {     title += "-Ashun";     console.log(title); //阿顺特烦恼-Ashun     return title;   })   .then((title) => {     title += "-Ashuntefannao";     console.log(title); //阿顺特烦恼-Ashun-Ashuntefannao   }); 
 
then 方法可以返回一个新的promise 对象,等返回的promise 确认状态后,才会执行后面的 then。后面的then 方法就是对新返回的promise 状态的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 new Promise((resolve, reject) => {   resolve("第一个promise"); }) .then(msg => {   console.log(msg);   return new Promise((resolve, reject) => {     setTimeout(() => {       resolve("第二个promise");     }, 3000);   }); }) .then(msg => {   console.log(msg); }); 
 
 
静态方法 Promise类还提供一些静态方法,能够更好的处理异步操作。
这些静态方法参数中若传入非Promise数据类型,则会将其转化为Promise,除了reject静态方法会默认将其转化为Promise.resolve,其余静态方法都会将其转化为Promise.resolve,数据本身作为返回结果。 
 
resolve 使用 promise.resolve(msg) 方法可以快速的返回一个状态为resolve的promise对象。
1 console.log(Promise.resolve("fulfilled"));	//Promise {<fulfilled>: "fulfilled"} 
 
1 2 3 4 5 6 7 8 9 10 11 12 {         let promise = new Promise((resolve, reject) => {           reject("promise state: rejected");         });         promise           .then(null, (rej) => {             console.log(rej);             return Promise.resolve("阿顺特烦恼");           })           .then((result) => console.log(result)); } 
 
若传入值为promise,后续then处理的是传入的promsie
1 Promise.resolve(Promise.reject("阿顺特烦恼")).catch((rej) =>console.log(rej)); 
 
下面将请求结果缓存,如果再次请求时直接返回带值的 promise
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function query(name) {   const cache = query.cache || (query.cache = new Map());   if (cache.has(name)) {     console.log("走缓存了");     return Promise.resolve(cache.get(name));   }   return ajax(`http://localhost:8083/users?name=${name}`).then(     response => {       cache.set(name, response);       console.log("没走缓存");       return response;     }   ); } query("阿顺").then(response => {   console.log(response); }); setTimeout(() => {   query("阿顺").then(response => {     console.log(response);   }); }, 1000); 
 
如果是 then able (具有then能力,类似promise)对象,会将对象包装成promise处理,这与其他promise处理方式一样的
1 2 3 4 5 6 7 8 const as = {   then(resolve, reject) {     resolve("阿顺特烦恼");   } }; Promise.resolve(as).then(value => {   console.log(value); }); 
 
若传入非Promise数据,默认将其转化为Promise.resolve,数据本身作为Promise.resolve的返回值
1 2 3 4 5 function getName() {   return "ashun"; } Promise.resolve(getName).then((result) => console.log(result())); //ashun 
 
reject 和 Promise.resolve 类似,reject 生成一个拒绝状态的promise
1 Promise.reject("fail").catch(error => console.log(error)); 
 
下面使用 Project.reject 设置状态
1 2 3 4 5 6 7 8 9 new Promise(resolve => {   resolve("阿顺特烦恼"); }) .then(v => {   if (v != "Ashuntefannao") return Promise.reject(new Error("not Ashuntefannao")); }) .catch(error => {   console.log(error); }); 
 
若传入非Promise数据,默认将其转化为Promise.reject数据本身作为Promise.reject的返回值
1 2 3 let obj = {name:"Ashun"}; Promise.reject(obj).catch((reason) => console.log(reason.name)); //Ashun 
 
all 使用Promise.all(promiseArr) 方法可以同时执行多个异步操作,比如页面加载时同进获取课程列表与推荐课程。
任何一个 Promise 执行失败就会调用 catch方法 
任何一个Promise没有确认状态,则all默认返回的promise状态也为pending,也就不会执行后续的then 
适用于一次发送多个异步操作 
参数必须是可迭代类型,如Array/Set 
成功后返回包含 promise 结果的有序数组 
若传入非Promise数据,则将其自动转化为Promise.resolve,数据本身作为返回值 
 
下例中当 p1、p2 两个 Promise 状态都为 fulfilled 时,p3状态才为fulfilled。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {         let p1 = new Promise((resolve) => {           setTimeout(() => {             resolve("p1 state: fulfilled");           }, 1000);         });         let p2 = new Promise((resolve, reject) => {           setTimeout(() => {             resolve("p2 state: fulfilled");           }, 2000);         });         let p3 = Promise.all([p1, p2]).then(           (result) => console.log(result),           (err) => console.log(err)         );  } 
 
若其中有一个promise状态为reject,则将调用Promise.all()后续then中的onReject,或catch方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {         let p1 = new Promise((resolve) => {           setTimeout(() => {             resolve("p1 state: fulfilled");           }, 1000);         });         let p2 = new Promise((resolve, reject) => {           setTimeout(() => {             reject("p2 state: reject");           }, 2000);         })         let p3 = Promise.all([p1, p2]).then(           (result) => console.log(result),           (err) => console.log(err)         ); } 
 
1 2 3 4 ………… let p3 = Promise.all([p1, p2]).catch(           (err) => console.log(err)         ); 
 
若某个状态为rejected的Promise已经被自身的then处理 , 那么该Promise最后返回的状态是fulfilled,(then默认返回状态为fulfilled的Promise )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 {         let p1 = new Promise((resolve) => {           setTimeout(() => {             resolve("p1 state: fulfilled");           }, 1000);         });         let p2 = new Promise((resolve, reject) => {           setTimeout(() => {             reject("p2 state: reject");           }, 2000);         }).then(null, (err) => err);         let p3 = Promise.all([p1, p2])           .then((result) => console.log(result))           .catch((err) => console.log("有promise状态为rejected"));                    // ["p1 state: fulfilled", "p2 state: reject"] } 
 
根据用户名获取用户,有任何一个用户获取不到时 promise.all 状态失败,执行 catch 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function ajax(url) {   return new Promise((resolve, reject) => {     let xhr = new XMLHttpRequest();     xhr.open("GET", url);     xhr.send();     xhr.onload = function() {       if (this.status == 200) {         resolve(JSON.parse(this.response));       } else {         reject(this);       }     };   }); } const api = "http://localhost:8083"; const promises = ["阿顺", "张三"].map(name => {   return ajax(`${api}/users?name=${name}`); }); Promise.all(promises)   .then(response => {     console.log(response);   })   .catch(error => {     console.log(error);   }); 
 
可以将其他非promise 数据添加到 all 中,它将被处理成 Promise.resolve,数据本身会被当做Promise.resolve的返回值
1 2 3 4 5 6 7 8 9 {         let getName = () => "Ashun";         let Age = 18;         let promise = new Promise((resolve) => resolve("阿顺特烦恼"));         Promise.all([getName, Age, promise]).then((result) =>           console.log(result)         );         // [ƒ, 18, "阿顺特烦恼"] } 
 
allSettled Promise.allSettled(PromsieArr),会将所有的Promsie视为已解决状态 ,会忽略拒绝状态的Promise,
拒绝状态的Promise信息,也会返回到最终的结果中。
返回包含Promise状态和结果的有序数组 
[{status:resolve/reject,value/reason},{…}] 
 
下面的p2 返回状态为 rejected ,但promise.allSettled 不关心,promise.allSettled始终将自身状态设置为 fulfilled 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {         const p1 = new Promise((resolve, reject) => {           resolve("p1 resolved");         });         const p2 = new Promise((resolve, reject) => {           reject("p2 rejected");         });         Promise.allSettled([p1, p2]).then((msg) => {           console.log(msg);         }); } # 执行结果  [ 	 {status: "fulfilled", value: "p1 resolve"}, 	 {status: "rejected", reason: "p2 rejected"}  ] 
 
下面是获取用户信息,但不关注某个用户是否获取不成功
1 2 3 4 5 6 7 8 const api = "http://localhost:8083"; const promises = [   ajax(`${api}/users?name=阿顺`),   ajax(`${api}/users?name=张三`) ]; Promise.allSettled(promises).then(response => {   console.log(response); }); 
 
其中若传入非promise数据类型,内部会转化为Promise.resolve,数据本身作为返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let arr = [           function () {             return "ashun";           },           { name: "ASHUN" },           18, 				]; Promise.allSettled(arr).then((result) => console.log(result)); # 结果 [ 	{status: "fulfilled", value: ƒ}, 	{status: "fulfilled", value: {…}}, 	{status: "fulfilled", value: 18}, ] 
 
race 使用Promise.race(promiseArr) 能够处理容错异步,且返回最快确定状态的Promise结果,和race单词一样哪个Promise快用哪个,哪个先返回用哪个。
以最快返回的promise为准 
如果最快返加的状态为rejected 那整个Promise.rece状态为rejected执行cache 
如果参数不是promise,内部将自动转为Promise.resolve 
 
下例体现Promise.rece的特性,哪个Promise最先确定状态,就返回谁的处理结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const p1 = new Promise((resolve, reject) => {   setTimeout(() => {     resolve("第一个Promise");   }, 2000); }); const p2 = new Promise((resolve, reject) => {   setTimeout(() => {     resolve("第二个异步");   }, 1000); }); Promise.race([p1, p2]) .then(results => {   console.log(results); }) .catch(msg => {   console.log(msg); }); // "第二个异步" 
 
可用其设置请求最长相应时间,下例:若请求在2秒内没有返回结果,则promise.race 状态失败,将会执行catch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const api = "http://localhost:8083"; const promises = [   ajax(`${api}/users.php?name=阿顺`),   new Promise((a, b) =>     setTimeout(() => b(new Error("request fail")), 2000)   ) ]; Promise.race(promises) .then(response => {   console.log(response); }) .catch(error => {   console.log(error); }); 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 {         let promises = [           new Promise((resolve) => {             setTimeout(() => {               resolve("请求成功");             }, 1200);           }),           new Promise((resolve, reject) => {             setTimeout(() => {               reject("请求超时");             }, 1100);           }),         ];         Promise.race(promises)           .then((result) => console.log(result))           .catch((reason) => console.log(reason)); } 
 
如果参数不是promise,内部将自动转为Promise.resolve,且数据本身作为Promise.resolve的返回值
1 2 3 4 5 6 7 8 9 10 {         let arr = [           function () {             return "ashun";           },           { name: "ASHUN" },           18,         ];         Promise.race(arr).then((result) => console.log(result())); //ashun } 
 
任务队列 实现原理 
如果在then中手动返回promise 时,后面的then 就是对返回的 promise 的处理 
通过链式调用then,不断处理返回的Promsie,解决任务队列中的任务。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let promise = Promise.resolve(); let p1 = promise.then(() => {   return new Promise(resolve => {     setTimeout(() => {       console.log(`p1`);       resolve();     }, 1000);   }); }); p1.then(() => {   return new Promise((a, b) => {     setTimeout(() => {       console.log(`p2`);     }, 1000);   }); }); 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 {         let promise = Promise.resolve();         promise = promise.then((result) => {           return new Promise((resolve, reject) => {             console.log("第一个then");             resolve(2);           });         });         promise = promise.then((index) => {           return new Promise((resolve, reject) => {             console.log(`第${index}个then`);             resolve(3);           });         });         promise = promise.then((index) => {           return new Promise((resolve, reject) => {             console.log(`第${index}个then`);             resolve(4);           });         }); } 
 
下面使用 Array.map 构建的队列,有以下几点需要说明
then 内部返回的 Promise 更改外部的 promise 变量 
为了让任务继续下去,执行完任务需要将 promise 状态修改为 fulfilled 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 {         function queue(tasks) {           let promise = Promise.resolve();           tasks.map((val, index) => {             promise = promise.then((result) => {               result && console.log(result);               return new Promise((resolve, reject) => {                 console.log(val);                 resolve(                   `第${index + 1}个任务执行完毕,第${index + 2}个任务开始执行`                 );               });             });           });         }         queue(["shun-1", "Ashun-2", "Ashuntefannao-3"]); } # 执行结果 shun-1 第1个任务执行完毕,第2个任务开始执行 Ashun-2 第2个任务执行完毕,第3个任务开始执行 Ashuntefannao-3 
 
下面再来通过 reduce 来实现队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 {         function queue(tasks) {           tasks.reduce((promise, val, index) => {             promise = promise.then((result) => {               result && console.log(result);               return new Promise((resolve, reject) => {                 console.log(val);                 resolve(                   `第${index + 1}个任务执行完毕,第${index + 2}个任务开始执行`                 );               });             });             return promise;           }, Promise.resolve());         }         queue(["shun-1", "Ashun-2", "Ashuntefannao-3"]); } 
 
高可用封装 上例中处理是在队列中完成,不方便业务定制,下面将Promise处理在剥离到外部
后台请求处理类 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 export default function(url) {   return new Promise((resolve, reject) => {     let xhr = new XMLHttpRequest()     xhr.open('GET', url)     xhr.send()     xhr.onload = function() {       if (this.status === 200) {         resolve(this.response)       } else {         reject(this)       }     }   }) } 
 
队列处理类 
1 2 3 export default function(promises) {   promises.reduce((promise, next) => promise.then(next), Promise.resolve()) } 
 
后台脚本 
1 2 3 4 5 6 7 8 <?php $users = [     1 => "小明",     2 => "李四",     3 => "张三" ]; sleep(1); echo $users[$_GET['id']]; 
 
使用队列 
1 2 3 4 5 6 7 8 9 <script type="module">   import queue from './queue.js'   import axios from './axios.js'   queue(     [1, 2, 3].map(v => () =>       axios(`user.php?id=${v}`).then(user => console.log(user))     )   ) </script> 
 
async/await  async/await 是promise 的语法糖,可以让编写 promise 更清晰易懂,也是推荐编写promise 的方式。
async/await 本质还是promise,只是更简洁的语法糖书写 
async/await 使用更清晰的结构来替换 promise.then/catch 的方式 
async/await能够让异步代码,以同步的形式 按顺序执行 
async声明的函数,会自动返回一个Promise。 
await必须在async声明的函数中使用。 
 
async 下面在 fun 函数前加上async,函数将默认返回一个状态为fulfilled的promise,函数体中使用return返回的数据,可以在后续的then中接收到
1 2 3 4 async function fun() { 				return "阿顺特烦恼"; 		} fun().then((result) => console.log(result)); 
 
若要按顺序处理多个异步代码块,使用传统的promise.then/catch在整个代码结构上,不如使用async/await清晰。
下例通过处理相同的问题,进行对比
使用传统Promise处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 {         function promise(text) {           return new Promise((resolve, reject) => {             resolve(text || "第一个then");           });         }         promise()           .then((result) => {             console.log(result);             return promise("第二个then");           })           .then((result) => {             console.log(result);             return promise("第三个then");           })           .then((result) => {             console.log(result);           }); } 
 
使用async/await处理可观察到,代码是按照同步形式执行的,结构更加清晰,代码量也减少了许多。
await相当于then,能够传递Promise的返回值 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 {         async function promise(text) {           return text || "第一个then";         }         async function run() {           let result1 = await promise();           console.log(result1);           let result2 = await promise("第二个then");           console.log(result2);           let result3 = await promise("第三个then");           console.log(result3);         }         run(); } 
 
await await关键词后面紧跟Promise,使用 await 关键词,可以接收所处理的Promise的返回值,并且等待该Promise确定状态后,才可执行后面的代码。
await 后面一般是promise,如果不是直接返回 
await 必须放在 async 定义的函数中使用 
await 用于替代 then 使编码更优雅 
 
下例会在 await 这行等待promise执行,直到 promise 确认状态后才执行后续代码。
1 2 3 4 5 6 7 8 9 10 async function fun() {   const promise = new Promise((resolve, reject) => {     setTimeout(() => {       resolve("Ashuntefannao");     }, 2000);   });   let result = await promise;   console.log(result); } fun(); 
 
我们知道:在then中不能够返回所处理的Promise本身,会产生死循环
1 let p1 = Promise.resolve().then((_) => p1); 
 
同理在async声明的函数中,也不能使用await处理函数本身。
等待fun返回的promise确认状态,而fun在调用时,又会等待自身。 
 
1 2 3 4 async function fun() { 	await fun(); } fun(); 
 
下面是请求后台获取用户课程成绩的示例
1 2 3 4 5 6 7 async function user() {   let user = await ajax(`http://localhost:8083/users?name=向军`);   let lessons = await ajax(     `http://localhost:8083/lessons?id=${user.id}`   );   console.log(lessons); } 
 
也可以将操作放在立即执行函数中完成
1 2 3 4 5 6 7 (async () => {   let user = await ajax(`http://localhost:8083/users?name=向军`);   let lessons = await ajax(     `http://localhost:8083/lessons?id=${user.id}`   );   console.log(lessons); })(); 
 
下面是使用async 设置定时器,并间隔时间来输出内容
1 2 3 4 5 6 7 8 9 10 11 12 async function sleep(ms = 2000) {   return new Promise(resolve => {     setTimeout(resolve, ms);   }); } async function run() {   for (const value of ["阿顺特烦恼", "Ashun"]) {     await sleep();     console.log(value);   } } run(); 
 
加载进度 下面是模拟请求后台查看进度,进度条展示的效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <style>       div {         width: 0px;         height: 30px;         border-radius: 3px;         overflow: hidden;         background-color: yellowgreen;         color: white;         text-align: center;       } </style> <body>     <div class="loading"></div> </body> <script>  {			  				//随机产生小于3秒的请求时间。         function randomTime() {           let max = 3;           let min = 1;           let multiple = Math.floor(Math.random() * (1000 - 100 + 1) + 100);           return Math.floor(Math.random() * (max - min + 1) + min) * multiple;         } 				//模拟请求延时。         async function request() {           return new Promise((resolve) => setTimeout(resolve, randomTime()));         }         let div = document.querySelector(".loading");         //请求任务队列         let requsets = [request, request, request, request, request];         let sum = 0;         requsets.map(async (req) => {           await req();           let percent = ++sum / requsets.length;           div.style.width = percent * 200 + "px";           if (percent == 1) {             div.innerHTML = "加载完毕";           } else {             div.innerHTML = percent * 100 + "%";           }         }); } </script> 
 
then able 和 Promise 一样,await 也可以操作then able 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class User {   constructor(name) {     this.name = name;   }   then(resolve, reject) {     let user = ajax(`http://localhost:8083/user?name=${this.name}`);     resolve(user);   } } async function get() {   let user = await new User("阿顺");   console.log(user); } get(); 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {         let user = {           name: "阿顺",           then(resolve, reject) {             return Promise.resolve().then((_) =>               setTimeout(resolve.bind(null, this.name), 1000)             );           },         };         async function run() {           let result = await user;           console.log(result);         }         run(); } 
 
对象、类中的方法,也可以用async/await处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 {         let user = {           name: "阿顺",           then(resolve, reject) {             return Promise.resolve().then((_) =>               setTimeout(resolve.bind(null, this.name), 1000)             );           },         };         let obj = {           async getName() {             let result = await user;             console.log(result);           },         };         obj.getName(); } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 class User {   constructor() {}   async get(name) {     let user = await ajax(       `http://localhost:8083/users?name=${name}`     );     user.name += "-Ashuntefannao";     return user;   } } new User().get("阿顺").then(resolve => {   console.log(resolve); }); 
 
声明形式 函数声明
1 2 3 4 5 6 async function get(name) {   return await ajax(`http://localhost:8083/users?name=${name}`); } get("阿顺").then(user => {   console.log(user); }); 
 
函数表达式
1 2 3 4 5 6 let get = async function(name) {   return await ajax(`http://localhost:8083/users?name=${name}`); }; get("阿顺").then(user => {   console.log(user); }); 
 
对象方法声明
1 2 3 4 5 6 7 8 9 let as = {   async get(name) {   	return await ajax(`http://localhost:8083/users?name=${name}`);   } }; as.get("阿顺").then(user => {   console.log(user); }); 
 
立即执行函数
1 2 3 4 5 6 7 (async () => {   let user = await ajax(`http://localhost:8083/users?name="阿顺"`);   let lessons = await ajax(      `http://localhost:8083/lessons?id=${user.id}`   );   console.log(lessons); })(); 
 
类方法中的使用
1 2 3 4 5 6 7 8 class User {   async get(name) {     return await ajax(`http://localhost:8083/users?name=${name}`);   } } let user = new User().get("阿顺").then(user => {   console.log(user); }); 
 
错误处理 async 内部发生错误,会将返回的promise状态置为rejected 状态,所以可以使用catch 来处理
1 2 3 4 5 6 async function as() {   console.log(shun); } as().catch(error => {   throw new Error(error); }); 
 
下面是异步请求数据不存在时的错误处理
1 2 3 4 5 6 7 async function get(name) {   return await ajax(`http://localhost:8083/users?name=${name}`); } get("阿顺小哥").catch(error => {   alert("用户不存在"); }); 
 
若await后的promise 被拒绝,并且没有使用then\catch处理,将抛出异常,可以使用 try...catch 处理错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 {         let users = ["阿顺", "Ashun", "shun"];         async function getUser(name) {         	let test = users.includes(name);           try {             await new Promise((res, rej) => {               console.log(test);               test ? res(test) : rej(`${name} not find`);             });           } catch (err) {             console.log(err);           }         }         getUser("阿顺A"); } 
 
多个 await 时当前面的出现失败且未处理,后面的将不可以执行
1 2 3 4 5 6 7 async function promiseQueue() {   await Promise.reject("fail");   await Promise.resolve("success").then(value => {     console.log(value);   }); } promiseQueue(); 
 
如果对前一个错误进行了处理,后面的 await 可以继续执行
1 2 3 4 5 6 7 async function promiseQueue() {   await Promise.reject("fail").catch(e => console.log(e));   await Promise.resolve("success").then(value => {     console.log(value);   }); } promiseQueue(); 
 
也可以使用 try...catch 特性忽略不必要的错误
1 2 3 4 5 6 7 8 9 async function promiseQueue() {   try {     await Promise.reject("fail");   } catch (error) {}   await Promise.resolve("success").then(value => {     console.log(value);   }); } promiseQueue(); 
 
也可以将多个 await 放在 try…catch 中统一处理错误
1 2 3 4 5 6 7 8 9 10 11 async function get(type) {   const host = "http://localhost:8083/"   try {     const goods = await ajax(`${host}/goodsList?type=${type}`);     const category = await ajax(`${host}/category?id=${goods.id}`);     console.log(lessons);   } catch (error) {     console.log("商品不存在");   } } get("new"); 
 
并发执行 有时需要多个await 同时执行,有以下几种方法处理,下面多个await 将产生等待
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 async function p1() {   return new Promise(resolve => {     setTimeout(() => {       console.log("Ashuntefannao");       resolve();     }, 2000);   }); } async function p2() {   return new Promise(resolve => {     setTimeout(() => {       console.log("Ashun");       resolve();     }, 2000);   }); } async function promises() {   await p1();   await p2(); } promises(); 
 
使用 Promise.all() 处理多个promise并行执行
1 2 3 4 5 …… async function promises() {   await Promise.all([p1(), p2()]); } promises(); 
 
先执行返回promise,再使用await处理结果
1 2 3 4 5 6 7 async function promises() {   let a1 = p1();   let a2 = p2();   await a1;   await a2; } promises();