08月08, 2022

JS进阶(10)--Promise(4)--async与await

async与await

消除回调

虽然我们有了Promise的规范,异步任务有统一的处理方式。

但是你会发现,其实现在有异步的情况,我们的代码还是不好写。

但是有了统一的处理方式,ES官方就可以对其进一步优化

ES7推出了两个重要的关键字asyncawait,用于更加优雅的表达Promise

async

async关键字用于修饰函数,被它修饰的函数,一定返回Promise

async function method1(){
  return 1; // 该函数的返回值是Promise完成后的数据
}

method1(); // Promise { 1 }

async function method2(){
  return Promise.resolve(1); // 若返回的是Promise,则method得到的Promise状态和其一致
}

method2(); // Promise { 1 }

async function method3(){
  throw new Error(1); // 若执行过程报错,则任务是rejected
}

method3(); // Promise { <rejected> Error(1) }

await

await关键字表示等待某个Promise完成,它必须用于async函数中

async function method(){
  const n = await Promise.resolve(1);
  console.log(n); // 1
}

// 上面的函数等同于
function method(){
  return new Promise((resolve, reject)=>{
    Promise.resolve(1).then(n=>{
      console.log(n);
      resolve(1)
    })
  })
}

要注意思考上面的问题: 为什么必须要把await放在一个async的函数中? 其实给我们的感觉

const n = await Promise.resolve(1);
console.log(n); // 1

这两句代码是分开的,实际上,这还是ES7给我们的一个语法糖,把await等代码包裹在一个async封装的函数中,其实就是放在then的回调函数中,就算我们在下面多写一些代码,这些代码也都是放在then的回调函数中的

思考:下面两段代码的打印结果是什么?并且解释一下为什么?

async function method(){
  const n = await Promise.resolve(1);
  console.log(n); 
  console.log("hello"); 
}
method();
console.log("world")
async function method(){
  console.log("hello"); 
  const n = await Promise.resolve(1);
  console.log(n); 
}
method();
console.log("world")

await也可以等待其他数据

async function method(){
  const n = await 1; // 等同于 await Promise.resolve(1)
}

如果需要针对失败的任务进行处理,可以使用try-catch语法

async function method(){
  try{
    const n = await Promise.reject(123); // 这句代码将抛出异常
    console.log('成功', n)
  }
  catch(err){
    console.log('失败', err)
  }
}

method(); // 输出: 失败 123

简单来说,有了awaitasync这两个关键字之后,以后我们调用异步代码,就可以像调用同步代码一样去调用,而不用去纠结调用异步函数的时候,值到底存不存在,比如之前的ajax代码:

const ajaxPromise = param => {
  return new Promise((resovle, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.open(param.type || "get", param.url, true);
    xhr.send(param.data || null);

    xhr.onreadystatechange = () => {
     if(xhr.readyState === 4){
      if(xhr.status === 200){
        resovle(JSON.parse(xhr.responseText));
      } else{
        reject(JSON.parse(xhr.responseText));
      }
     }
    }
  })
}

这是我们封装的ajaxPromise函数,我们现在可以这样调用:

async function test(){
  let data = await ajaxPromise({
    url:"/users",
  })

  console.log(data);
  setHTML(data);
}

test();

就像获取一般函数的返回值一样去使用他即可。

这样子的话,我们再回到之前找工作的那个问题上,之前困扰我们的是,我们只有等着上一家的回复之后,才能继续在回调函数中写代码,但是现在有了awaitasync就完全解决了我们的问题,我们甚至可以像同步代码一样,直接写个循环就行了

async function test() { 
  let companies = ["华为", "小米", "京东", "天美"];
  try { //如果是reject状态,直接try...catch...捕获异常原因

    //循环公司名称,依次发送简历
    for (let i = 0; i < companies.length; i++) {
      let d = await sendMessage(companies[i]);
      if (d.pass) { //如果简历通过直接退出循环
        console.log(d.msg);
        break;
      }
      else { 
        console.log(d.msg);
      }
    }
  } catch (e) { 
    console.log(e);
  }
}
test();

本文链接:http://www.yanhongzhi.com/post/js_ap_25.html

-- EOF --

Comments