• javascript ES6 新特性之 Promise,ES7 async / await


    es6 一经推出,Promise 就一直被大家所关注。那么,为什么 Promise 会被大家这样关注呢?答案很简单,Promise 优化了回调函数的用法,让原本需要纵向一层一层嵌套的回调函数实现了横向的调用,也就是链式调用。

    我们先来看下面的代码:

    1 function getData(){
    2     setTimeout(()=>{
    3         var name = "zhangsan";
    4     }, 1000)
    5 }
    6 
    7 getData();

    在上面的代码中,我们模拟了一个异步时间,一秒后输出 name = "zhangsan"; 那如何当我们调用 getData() 方法的时候拿到这个 name 值呢,这时可能会有人说 return 出来就可以了,如下:

    1 function getData(){
    2     setTimeout(()=>{
    3         var name = "zhangsan";
    4     }, 1000);
    5     return name
    6 }
    7 
    8 console.log(getData()); // ReferenceError: name is not defined

    结果却报错,这时由于当我们执行 getData() 函数的时候,由于 setTimeout 异步执行,所以先执行第五行的 return name;一秒之后才声明 name = "zhangsan"; 所以会 name is not defined 的错。

    那有人可能就会说把 return 放到 setTimeout 里面执行,如下:

    1 function getData(){
    2     setTimeout(()=>{
    3         var name = "zhangsan";
    4         return name
    5     }, 1000);
    6 }
    7 
    8 console.log(getData()); // undefined

    仍然拿不到 name 值,报 undefined 的错,这个原因就很简单了,因为执行 getData() 的时候,方法没有返回值,所以报 undefined,一秒之后再执行 setTimeout。

    通过以上报错我们可以知道,setTimeout 执行完成后才能拿到 name 的值,所以我们就需要在执行结束后再通过回调的方式拿到 name 的值,如下:

     1 function getData(callback){
     2     setTimeout(()=>{
     3         var name = "zhangsan";
     4         callback(name)
     5     }, 1000)
     6 }
     7 
     8 getData((data)=>{
     9     console.log(data) // zhangsan
    10 });

    我们在 getData() 方法内出入一个回调函数,当 setTimeout 执行结束后调用此方法并将 name 值传入,这样我们就能拿到 name 值了。这里我们用到了 ES6 的另一个特性 箭头函数,我们姑且先将它 ( ) => { } 和 function( ){ } 看做是等价的。

    上述方法可以解决我们的问题,但是在代码上我们就需要再多些一个回调函数,这样看起来很不友好,所以 ES6 为我们提供了 Promise 这个特性。

    1 var p = new Promise((resolve, reject) => {
    2     setTimeout(() => {
    3         var name = "zhangsan";
    4         resolve(name)
    5     }, 1000)
    6 });
    7 p.then((data) => {
    8     console.log(data);
    9 });  // zhangsan

    上面的代码等同于下面的:

     1 function getData(resolve, reject) {
     2     setTimeout(() => {
     3         var name = "zhangsan";
     4         resolve(name)
     5     }, 1000)
     6 }
     7 
     8 var p = new Promise(getData);
     9 
    10 p.then((data)=> {
    11     console.log(data);
    12 });  // zhangsan

    我们可以看出,Promise 构造函数接受一个函数作为参数,函数里面有两个参数 resolve 和 reject ,其中 resolve 作为执行成功的函数, reject 作为执行失败的函数。如下:

     1 function getData(resolve, reject) {
     2     setTimeout(() => {
     3         var name = "zhangsan";
     4         if(Math.random() < .5){
     5             resolve(name)
     6         } else{
     7             reject("获取 name 失败")
     8         }
     9     }, 1000)
    10 }
    11 
    12 var p = new Promise(getData);
    13 
    14 p.then((data)=> {
    15     console.log(data);   // zhangsan
    16 },(data)=>{
    17     console.log(data);   // 获取 name 失败
    18 }) ;

    我们定义一个随机数,当随机数小于 0.5 时会走 p.then() 的第一个函数,也就是正确的 resolve,当随机数大于 0.5 时,会走第二个函数,也就是错误的 reject。

    Promise 除了 then 之外还提供了一个一个 catch 的方法,如下:

     1 function getData(resolve, reject) {
     2     setTimeout(() => {
     3         var name = "zhangsan";
     4         resolve(name)
     5     }, 1000)
     6 }
     7 
     8 var p = new Promise(getData);
     9 
    10 p.then((name)=> {
    11     console.log(name);   // zhangsan
    12     console.log(age)
    13 }).catch((reason)=>{
    14     console.log(reason)  // ReferenceError: age is not defined
    15 }) ;

    在上面的代码中我们在 p.then() 的方法内输出了一个 age ,但是这个 age 我们既没有在全局定义,也没有通过传值的方式传过来,如果我们不写底下的 catch() 方法的话会报 ReferenceError: age is not defined,同时程序会崩掉,加上 .chath 方法后 ReferenceError: age is not defined 会在此方法内输出,程序并不会崩掉,这个就类似于我们常用的 try / catch 方法。

    在 ES7 中,还给我们提供了更为方便的异步操作方法 async / await ;如下:

     1 async function getData() {
     2     return new Promise((resolve, reject) => {
     3         setTimeout(() => {
     4             var name = "zhangsan";
     5             resolve(name)
     6         }, 1000)
     7     })
     8 }
     9 
    10 async function test() {
    11     var data = await getData();
    12     console.log(data);
    13 }
    14 
    15 test();  // zhangsan

    我们将之前的代码改为上面这样,输出结果依然是 zhangsan,这里使用了 async / await 的组合,我们将上面的代码简化一下:

     1 async function getData() {
     2     var name = "zhangsan";
     3     return name;
     4 }
     5 
     6 console.log(getData());  // Promise { 'zhangsan' }
     7 
     8 async function test(){
     9     var data = await getData();
    10     console.log(data);
    11 }
    12 
    13 test();  // zhangsan

    我们在 function getData( ){ } 前面加了一个 async 的字段,该函数就被认定为一个异步函数,然后在调用 getData( ) 的方法前面加一个 await 的字段,这就是一个异步操作,意思就是等 getData( ){ } 异步函数执行完以后再调用此方法,这样我们在 getData() 的函数内加一个 setTimeout 的异步方法后,也是等异步方法执行完以后在调用,这样就能拿到 name = "zhangsan" 的值了。

  • 相关阅读:
    2015南阳CCPC G
    2015南阳CCPC D
    2015南阳CCPC C
    2015南阳CCPC A
    Codeforces Round #327 (Div. 2) E. Three States bfs
    Codeforces Round #327 (Div. 2) B. Rebranding 模拟
    Codeforces Round #327 (Div. 2)C. Median Smoothing 构造
    SEO那些事:一句代码一键分享网站
    用原型链的方式写一个类和子类
    用原型链的方式写一个类和子类
  • 原文地址:https://www.cnblogs.com/weijiutao/p/10631565.html
Copyright © 2020-2023  润新知