属于,async是es6的新特性,用于表明程序里面可能有异步过程。用async关键字声明的函数返回的是一个promise对象,如果在函数中return一个直接量,async会把这个直接量通过promise.resolve()封装成promise对象;当async函数没有返回值时,返回“promise.resolve(undefined)”。
本教程操作环境:windows7系统、ecmascript 6版、dell g3电脑。
es6新特性 async和await关键字1、初步了解我们先从字面意思来理解这两个关键字,async是asynchronous(异步)的简写,而await可以认为是async wait的简写。所以async可以理解为用于声明一个函数是异步的,而await用于等待一个异步任务执行完成。
async和await关键字让我们可以用一种更简洁的方式写出基于promise的异步行为,而无需刻意地链式调用promise。
接下来我们通过先几个例子,初步了解一下async和await的作用。
知识点1: 用 async 关键字声明的函数返回的是一个 promise 对象。如果在函数中 return 一个直接量,async 会把这个直接量通过 promise.resolve() 封装成 promise 对象。当 async 函数没有返回值时,返回 promise.resolve(undefined)
//定义一个普通函数,返回一个字符串 function test() { return hello async; } const result1 = test(); console.log(result1); //输出一个字符串 hello async //定义一个使用了async修饰的函数,同样返回一个字符串 async function testasync() { return hello async; } const result2 = testasync(); console.log(result2); //输出一个promise对象 promise {<fulfilled>: 'hello async'}
//async较好的用法 async function testasync(){ //返回一个promise对象 return new promise((resolve, reject)=>{ //处理异步任务 settimeout(function () { resolve(testasync) }, 1000); }) } //async通常用于声明一个处理异步任务且返回了promise对象的函数
知识点2: await关键字只能使用在被async声明的函数内,用于修饰一个promise对象,使得该promise对象处理的异步任务在当前协程上按顺序同步执行。
//定义一个使用async修饰的函数,处理异步任务 async function testasync(){ return new promise((resolve, reject)=>{ settimeout(function () { resolve(testasync) }, 1000); }) }
//定义一个函数,直接调用testasync函数 function testawait(){ console.log('testasync调用前') testasync().then(res=>{ console.log(res) //输出testasync }) console.log('testasync调用后') } /***** 输出如下 *****/ testasync调用前 testasync调用后 testasync //尽管代码按顺序写,但不按顺序执行,因为testasync()是异步函数
//定义一个函数(不使用async声明该函数)用await修饰调用testasync函数 function testawait(){ console.log('testasync调用前') await testasync().then(res=>{ //使用await关键字修饰 console.log(res) }) console.log('testasync调用后') } //调用testawait()函数 testawait() //报错:uncaught syntaxerror: await is only valid in async functions and the top level bodies of modules,因为await只能使用在被async修饰的函数内。
//定义一个函数(使用async声明该函数)用await修饰调用testasync函数 async function testawait(){ console.log('testasync调用前') await testasync().then(res=>{ console.log(res) }) console.log('testasync调用后') } /***** 输出如下 *****/ testasync调用前 testasync testasync调用后 //使用了await关键字修饰,使得代码按照顺序执行,即同步执行
2、async关键字(1)用于表明程序里面可能有异步过程
(2)async函数返回值的类型为promise对象: 这是和普通函数本质上不同的地方,也是使用时重点注意的地方;
return newpromise( ),这个用法符合async函数本意;return data,特别注意到是这样子写相当于promise.resolve(data),返回的data被封装成一个promise对象,但是在调用async函数的地方通过简单的=是拿不到这个返回值data的,因为返回值是一个promise对象,所以需要用.then(data => { })方式才可以拿到这个data;如果没有返回值,相当于返回了promise.resolve(undefined);(3)无等待,非阻塞:使用async关键字声明的函数里面如果有异步过程可能会等待,但是函数本身会马上返回,不会阻塞当前主线程。如果在函数里面使用了await关键字修饰的异步过程,其工作在相应的协程上,会阻塞等待异步任务的完成再返回。
//定义一个函数,处理异步任务(使用定时器模拟),返回一个promise对象 async function testasync(){ return new promise((resolve, reject) => { settimeout(function () { resolve(成功调用testasync) }, 1000); }); } //定义一个函数,使用await关键字修饰调用testasync()函数 async function testawait(){ //使用了await关键字修饰调用testasyn()函数 await this.testasync().then(res=>{ console.log(res) //输出的是testasync()函数resolve的值 }); console.log(helloasync); } //主线程 console.log('testawait调用前') testawait(); console.log('testawait调用后') /***** 输出结果如下 *****/ testawait调用前 testawait调用后 //因为testawait()函数使用了async关键字修饰,所以不会阻塞主线程的执行,所以这两句话会先直接输出,然后再执行testawait()函数 成功调用testasync //因为testawait()函数在内部调用testasync()函数时使用了await关键字修饰,所以在对应的协程上会阻塞,等待testasync()函数执行完,再输出下面那句'helloasync' helloasync
3、await关键字(1)await只能在async函数内部使用:不能放在普通函数里面,否则会报错。
(2)await关键字后面跟的是一个promise对象。如果跟的是一个函数,则这个函数应当返回一个promise对象。如果跟的是非promise对象,则会通过promise.resolve( )函数自动将这个东西包装成一个promise对象并置于fulfilled状态。
//例如: const a = await 'hello await' // 相当于 const a = await promise.resolve('hello await'); console.log(a) //输出 'hello await'
(3)await的本质是等待它所修饰的promise对象的fulfilled状态,并把resolve(data)的数据data返回。
意思是,如果await后面跟的是一个 promise 对象,await 就会阻塞后面的代码,等着 promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。
async function testasync(){ return new promise((resolve, reject) => { settimeout(function () { resolve(成功调用testasync) }, 1000); }); } const a = await testasync() //这里的a就会拿到testasync函数resolve的数据 console.log(a) //在一秒后输出'成功调用testasync'
(4)await并不关心它所修饰的promise对象的rejected状态,即reject(data)的数据data并不会被await处理,所以建议通过promise对象调用catch去捕获。
async testawait(){ //变量a用于接收testasync()函数resolve的数据 let a = await testasync().catch(err=>{ //处理异常和reject的数据 }) }
4、深入讲解async和await(1)执行顺序
//定义一个函数,该函数接收一个参数,1s后再返回参数的两倍 async function double(num) { return new promise((resolve, reject) => { settimeout(() => { //使用定时器模拟异步任务 resolve(2 * num) //将运算结果交给resolve }, 1000); }) } async function getresult () { console.log('double调用前') //顺序:2 let result = await double(10); //将10作为参数传递给double函数 //result变量用于接收double()函数resolve的值 console.log(result); //顺序:4 console.log('double调用后') //顺序:4 } console.log('getresult调用前') //顺序:1 getresult(); console.log('getresult调用后') //顺序:3 /***** 依次输出如下 *****/ getresult调用前 double调用前 getresult调用后 20 //1s后输出 double调用后
①首先打印输出getresult调用前,同步代码,顺序执行;
②然后调用方法getresult( ),打印输出double调用前,同步代码,顺序执行;
③再调用异步方法double( )
如果此处没有使用await关键字修饰,则依次输出的是:getresult调用前、double调用前、double调用后、getresult调用后、1s后输出20
因为异步操作不会影响其他代码的执行,所以会将其他代码按顺序执行完,最后再执行double函数
因为这里使用了await关键字,所以getresult( )的代码执行到这里就会被阻塞,等到double函数resolve了,再往下执行
④尽管getresult函数内部被await阻塞了,由于getresult函数本身也是个async函数,所以它不会影响getresult函数外面的代码执行。因为调用async函数不会造成阻塞,它内部的所有阻塞都被封装在一个promise对象中异步执行。
⑤所以在调用getresult函数后,会继续向下执行,即打印输出getresult调用后
⑥当1s之后,异步函数double执行完成,将结果交给resolve。
⑦通过await关键字接收到double函数resolve的值,赋值给result变量。打印输出20
⑧因为使用了await阻塞将异步变为同步,所以在打印输出20后再打印输出double调用后
(2)处理reject回调
//方法一:通过promise对象的catch进行捕获 function a(){ return new promise((resolve,reject) => { settimeout(() => { reject(something) }, 1000) }) } async function b(){ let r = await a().catch((err)=>{ console.log(err) }) }
//方法二:通过try/catch语句处理 function a(){ return new promise((resolve,reject) => { settimeout(() => { reject(something) }, 1000) }) } async function b(){ let r = null try{ r = await a() }catch(err){ console.log(err) } }
(3)使用await优化promise对象的回调地狱问题
在promise章节中我们通过了promise对象的then( )方法链式调用解决了回调地狱问题,但看起来仍然不够美观,我们可以通过await优化一下,让它看起来更符合我们平时代码的编写习惯。
//原本的解决方案 //第二个请求依赖于第一个请求的返回值,第三个请求依赖于第二个请求的返回值 request1().then(function(data){ return request2(data) }).then(function(data){ return request3(data) }) //这里只发送了三次请求,代码看起来还不错,虽然它已经比普通的回调函数形式好了很多。 //那如果需要发送五次或十次请求呢?代码也许会没那么美观,接下来我们使用学习到的await去解决这个问题。
原本的要求是每个请求都依赖于上一个请求的返回值,那么是不是得等一个请求完,才能发送下一个请求?这时我们可以思考一下,await的作用是什么?是不是对一个promise对象去进行阻塞,使其状态变为fulfilled后获取resolve的值。这不就正是我们所需要的。
//使用await的解决方案 var res1 = await request1() //将request1的返回值赋值给res1 var res2 = await request2(res1) //将res1作为参数传给request2,并将request2的返回值赋值给res2 var res3 = await request3(res2) //同理 //这样子写的代码更加的美观,并且更符合我们平时编写代码的习惯
【相关推荐:javascript视频教程、编程视频】
以上就是async属于es6属性吗的详细内容。