- Vue.js 3应用开发与核心源码解析
- 吕鸣
- 1535字
- 2023-08-31 19:30:32
1.5.3 Promise和async/await
1.Promise
Promise是一种适用于异步操作的机制,比传统的回调函数解决方案更合理和更强大。从语法上说,Promise是一个对象,从它可以获取异步操作的结果:成功或失败。在Promise中,有三种状态:pending(进行中)、resolved(已成功)和rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,无法被Promise之外的方式改变。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。创建一个Promise对象,代码如下:
var promise = new Promise(function(resolve, reject) { ... if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } });
在上面的代码中,创建了一个Promise对象,Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。这是两个内置函数,resolve函数的作用是将Promise对象的状态变为“成功”,在异步操作成功时调用,并将异步操作的结果作为参数传递出去;reject函数的作用是将Promise对象的状态变为“失败”,在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去。当代码中出现错误(Error)时,就会调用catch回调方法,并将错误信息作为参数传递出去。
Promise对象实例生成后,可以用then方法分别指定resolved(成功)状态和rejected(失败)状态的回调函数以及catch方法,比如:
promise.then(function(value) { // success逻辑 }, function(error) { // failure逻辑 }).catch(function(){ // error逻辑 });
then()方法返回的是一个新的Promise实例(不是原来那个Promise实例)。因此,可以采用链式写法,即then()方法后面再调用另一个then()方法,比如:
getJSON("/1.json").then(function(post) { return getJSON(post.nextUrl); }).then(function (data) { console.log("resolved: ", data); }, function (err){ console.log("rejected: ", err); });
下面是一个用Promise对象实现的Ajax操作get方法的例子。
var getJSON = function(url) { // 返回一个Promise对象 var promise = new Promise(function(resolve, reject){ var client = new XMLHttpRequest(); //创建XMLHttpRequest对象 client.open("GET", url); client.onreadystatechange = onreadystatechange; client.responseType = "json"; //设置返回格式为json client.setRequestHeader("Accept", "application/json");//设置发送格式为json client.send();//发送 function onreadystatechange() { if (this.readyState !== 4) { return; } if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; }); return promise; }; getJSON("/data.json").then(function(data) { console.log(data); }, function(error) { console.error(error); });
了解Promise的基本知识可以便于后续学习使用服务端渲染。当然,Promise的应用场合还是比较多的,如果想要深入了解,可以访问网址:https://developer.mozilla.org/en-US/docs/Web/Java Script/Reference/Global_Objects/Promise,进行系统的学习。
2.async/await
async/await语法在2016年就已经提出来了,属于ES 7中的一个测试标准(目前来看是直接跳过ES 7,列为ES 8的标准了),它主要为了解决下面两个问题:
· 过多的嵌套回调问题。
· 以Promise为主的链式回调问题。
前面讲解过Promise,虽然Promise解决了恐怖的嵌套回调问题,但是解决得并不彻底,过多地使用Promise会引发以then为主的复杂链式调用问题,同样会让代码阅读起来不那么顺畅,而async/await就是它们的救星。
async/await是两个关键字,主要用于解决异步问题,其中async关键字代表后面的函数中有异步操作,await关键字表示等待一个异步方法执行完成。这两个关键字需要结合使用。
当函数中有异步操作时,可以在声明时在其前面加一个关键字async,代码如下:
async function myFunc() { //异步操作 }
使用async声明的函数在被调用时会将返回值转换成一个Promise对象,因此async函数通过return返回的值会进入Promise的resolved状态,成为then方法中回调函数的参数,代码如下:
// myFunc()返回一个Promise对象 async function myFunc() { return 'hello'; } // 使用then方法就可以接收到返回值 myFunc().then(value => { console.log(value); // hello })
如果不想使用Promise的方式接收myFunc()的返回值,可以使用await关键字更加简洁地获取返回值,代码如下:
async function myFunc() { return 'hello'; } let foo = await myFunc(); // hello
await表示等待一个Promise返回,但是await后面的Promise对象不会总是返回resolved状态,如果发生异常,则进入rejected状态,那么整个async异步函数就会中断执行,为了记录错误的位置和编写异常逻辑的代码,需要使用try/catch,代码如下:
try { let foo = await myFunc(); // hello }catch(e){ // 错误逻辑 console.log(e) }
下面举一个例子,在后面的实战项目开发中,经常会用到数据接口请求数据,接口请求一般是异步操作,例如在Vue的mounted方法中请求数据,代码如下:
async mounted () { // 代码编写自上而下,一行一行,以便于阅读 let resp = await ajax.get('weibo/list') let top = resp[0] console.log(top) }
在上面的代码中,ajax.get()方法会返回一个Promise,采用await进行了接收,并且await必须包含在一个用async声明的函数中。
可以看出,在使用了async/await之后,整个代码的逻辑更加清晰,没有了复杂的回调和烦琐的换行。
至此,对于实战项目中用到的相关ES 6语法基本讲解完毕,如果读者想进一步了解ES 6的更多语法知识,可以自行在其官网上学习。