async/await 与 Promise 详解

async 

是什么?

async  中文翻译过来是 “异步,非同步,异步通信” 的意思。

async 是 ES7 才有的与异步操作有关的关键字,和 Promise , Generator 有很大关联的。

注:ES7/8/9 都是 ES6 的补充

 

怎么用?

语法

async function name([param[, param[, ... param]]]) { statements }
// name: 函数名称。
// param: 要传递给函数的参数的名称。
// statements: 函数体语句。

返回值

  async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。

async function helloAsync(){
    return "helloAsync";
  }
  
console.log(helloAsync())  // Promise {<resolved>: "helloAsync"}
 
helloAsync().then(v=>{
   console.log(v);         // helloAsync
})

既然说到了 async  函数,那就必然少不了要说说 await 。

 

await  

是什么?

await  中文翻译过来的意思是 “等待,暂停函数的执行,等待异步任务完成”

async 函数中 可能 会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后(这个异步操作是 Promise对象的返回结果 ),得到了 Promise 对象返回结果之后恢复 async 函数的执行并返回解析值。如果 async  函数中 没有 await  表达式,这个函数就跟 普通的函数一样没有太大的差别了。

 

怎么用?

await 关键字仅在 async function 中有效。如果在 async function 函数体外使用 await ,你只会得到一个语法错误。

 

 语法:

function testAwait(){
   return new Promise((resolve, reject) => {
       setTimeout(function(){
          console.log("testAwait");
          resolve();
       }, 1000);
   });
}
 
async function helloAsync(){
   await testAwait();
   console.log("helloAsync");
 }
helloAsync();
// testAwait
// helloAsync

 

上文中有说到:await 等待的是 Promise 对象的返回结果。如果等待的不是 Promise 对象,则返回该值本身。

function testAwait(){ 
    console.log("testAwait"); 
} 
async function helloAsync(){ 
    await testAwait(); 
    console.log("helloAsync"); 
} 

helloAsync();

// testAwait 
// helloAsync

综上,await针对所跟不同表达式的处理方式:

  • Promise 对象:await 会暂停执行,等待 Promise 对象 resolve,然后恢复 async 函数的执行并返回解析值。
  • 非 Promise 对象:直接返回对应的值。

说了 async / await  自然就要说说 Promise。

 

Promise

说到 Promise , 不得不说说异步。

//(此处Promise文案基本摘抄于廖大大的文章,文末有给出地址。此处列出详细的内容,是便于自己学习。)

在 JavaScript 世界中,所有的代码都是单线程执行的。由于这个 “缺陷”,导致JavaScript的所有网络操作浏览器事件都必须是异步执行。而又由于 ajax 产生的地狱回调,Promise 应运而生。

 

是什么?

Promise 是 ES6 中的一个内置对象,本身是一个构造函数,通过 new 可以创建一个 Promise 对象。

 

用来干嘛的?

  1、用于异步计算

  2、将异步操作队列化,按照期望的顺序执行,并返回预期的结果。

 

怎么用?

new Promise((resolve, reject) => {
   setTimeout(function () {
        if (...) {
           ...
            resolve('success');
        }
        else {
            reject('error');
        }
    }, timeOut * 1000);
}).then(function (result) {
    console.log('成功:' + result);
}).catch(function (reason) {
    console.log('失败:' + reason);
})

// 或者可写成
var p1 = new Promise((resolve, reject) => {
   setTimeout(function () {  // setTimeout  此处只是用来模拟一个网络请求,
        if (...) {
           ...
            resolve('success');
        }
        else {
            reject('error');
        }
    }, timeOut * 1000);
})

// 如果成功,执行这个函数:
var p2 = p1.then(function (result) {
    console.log('成功:' + result);
});

// 如果失败,执行这个函数:
var p3 = p2.catch(function (reason) {
    console.log('失败:' + reason);
});

 由上文可见,Promise 的最大好处就是在异步执行的过程中,把执行代码和处理结果进行了分离。这样能避免地狱回调,更利于猿们后期的维护。

 

说到 Promise 的基本用法,不得不说说 Promise 的串行用法。

比如,有多个异步任务,我们需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续 并 执行错误处理函数。代码如下:

job1.then(job2).then(job3).catch(handleError)  // job1, job2, job3  都是Promise 对象

 

Promise 不止有串行的用法,也可以并行执行异步任务。

比如一个页面中,一进入这个页面,我们需要从两个(或者更多)不同的URL 分别获取该页面的信息,这时候,这两个任务可以是并行执行的。用 Promise 实现如下:

var p1 = new Promise(function (resolve, reject){ ... })

var p2 = new Promise(function (resolve, reject){ ... })

// 同时执行 p1 和 p2 , 并在他们都完成之后执行 then
Promise.all([p1, p2]).then(function (results) {
    console.log(results) // 获得一个 Array:['p1', 'p2']
}) 

 

然而有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});

由于 p1 执行较快,Promise 的 then() 将获得结果 ‘p1’。p2 仍在继续执行,但执行结果将被丢弃。

 

 async/await  与  Promise  的区别

对比两个方法来处理异步。代码如下:

function getApi () {
  return new Promise((resolve, reject) => {
       setTimeout(function () { // 模拟发请求
            if (...) {
               ...
               resolve('success');
            }else {
                reject('error');
            }
        }, 1000);
    })  
}

// async / await  方法
async function name () {
    try{ 
        let res = await getApi()
        done(res)    
        return result
    }catch(error){
        ...
    }
}

//Promise
getApi().then( resolve =>{
    ...
    done(resolve)
    return result
}).catch( error =>{
  ...
})

由上文可以看出来:

async / await  处理起异步任务来,比Promise 更直观些;

async / await 对异常的处理比 Promise  更完善。 因为当 Promise 的 then() 方法中出现了异常,是不会被抛给 catch() 的, 这时候就需要我们再去嵌套一层 try... catch。

 

另外我们说说题外话:

处理异步任务的几种方法:

1、回调函数

2、事件监听

3、发布 / 订阅

4、Promise

5、async / await

 

 

相关文章推荐:

axios、fetch 和 ajax 等的区别详解

彻底弄清Promise、Generator以及Async/await

廖雪峰大大关于 Promise 的文章: https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544

 这一次,彻底弄懂 JavaScript 执行机制:从promise、process.nextTick、setTimeout出发,谈谈Event Loop中的Job queue

 

posted on 2019-11-04 15:50  bala001  阅读(740)  评论(0编辑  收藏  举报

导航