异步函数,async,await那些你忽略的进程

异步函数

  • 异步函数,也称为async/await(语法关键字),是es6promise在JS函数中的应用,这个特性从行为和语法上都加强了JS,让以同步方式写的代码可以异步执行

例子1:这个期约在超时以后会解决为一个值,若是程序中其余代码要访问这个值,则须要一个解决处理函数es6

let p = new Promise((resolve, reject) => 
setTimeout(resolve, 1000, 3)); p.then((x) => console.log(x)); // 3 复制代码

async

  • async关键字用于声明异步函数,这个关键之能够用在函数声明,函数表达式,箭头函数和方法上,这个关键字可让函数具备异步的特性,但整体上代码任然是同步求值得,在参数和闭包方面,异步函数任然具备普通JS函数的正常行为
async function foo() {
 console.log(1);  return 3;  } // 给返回的期约添加一个解决处理程序  foo().then(console.log);  console.log(4);  console.log(5); // 1 ,4 ,5 , 3 复制代码

小结:在异步函数若是使用了return返回了值,这个值会被promise.resolve()包装成一个期约函数,异步函数始终返回期约对象,在函数外部调用能够获得他返回的期约promise

  • 异步函数的返回值期待一个thenable接口的对象,这个对象能够提供给then()的处理程序解包,若是不是,就会被当作已经解决期约结果
// 返回一个没有实现thenable接口的对象
 async function bar() {  return ['bar'];  }  bar().then(console.log); // ['bar'] // 返回一个实现了thenable接口的非期约对象  async function baz() {  const thenable = {  then(callback) {  callback('baz');  }  };  return thenable;  }  baz().then(console.log); // baz  // 返回一个期约  async function qux() {  return Promise.resolve('qux');  }  qux().then(console.log); // qux 复制代码

小结:异步函数返回值,含thenable则提供then的处理程序解包,不然把返回值当期约处理结果,可是要注意,拒绝期约的错误不会被异步函数捕获浏览器

async function foo() {
 console.log(1);  Promise.reject(3);  }  // Attach a rejected handler to the returned promise   foo().catch(console.log);  console.log(2);  // 1  // 2   // Uncaught (in promise): 3 复制代码

await

  • 由于异步函数主要针对不会立刻完成的任务,因此须要一种暂停和恢复执行的能力,使用await能够暂停异步函数的代码执行,等待期约解决
//异步写法
 let p = new Promise((resolve, reject) =>  setTimeout(resolve, 1000, 3));  p.then((x) => console.log(x)); // 3 //async写法  async function foo() {  let p = new Promise((resolve, reject) =>  setTimeout(resolve, 1000, 3));  console.log(await p);  } 复制代码

小结:await关键字会暂停执行异步函数后面的代码,让出JS运行时的执行线程,这个行为和生成器中的yield关键字同样,await关键字一样是尝试解包对象的值,而后将这个值传达给表达式,,再异步恢复异步函数的执行markdown

接下来看一个涉及中止与恢复执行的例子:这个例子很是有意思,虽然如今你看不到这种效果,可是能更直白帮你理解await

  • 为了更好的理解这个例子,首先要知道这几个问题闭包

    • await的地方,等于局部暂停,等待返回值,继续其余线程异步

    • 一样的await按照前后顺序从上往下async

    • 当await有多个进程之后,会按照多列顺序执行函数

      例子1:oop

async function foo() {
 console.log(await Promise.resolve('foo'));  }  async function bar() {  console.log(await 'bar');  }  async function baz() {  console.log('baz');  }  foo();  bar();  baz();  // baz // bar // foo 复制代码

小结:正常状况是这个顺序,可是你在浏览器跑的时候,结果bar和foo的值会调换位子ui

首先咱们说一下执行原理:

  • foo()调用时,foo在消息队列添加两列进程,第一列等待返回值,第二列拿到返回值后执行的进程,
  • 而后继续bar()这时候在消息队列第一列添加一个进程,这时候执行baz,直接打印出‘baz',
  • 而后开始消息队列进程,foo第一列期约得出结果拿到返回值,而后继续bar的消息队列第一列进程,这时候打印出'bar',这时候消息队列第一列进程所有执行完毕,
  • 进入第二列,foo用第一列进程拿到的返回值执行进程,打印foo,

其次咱们说一下为何浏览器的结果不是这样:1TC39 对 await 后面是期约的状况如何处理作过一次修改。修改后,本例中的 foo()里的await Promise.resolve(’foo‘)只会生成一个异步任务。因此他执行的时候没有两列,只有一列,因此会按await顺序排列

  • 按照上面理解,咱们来看最终的一个例子
async function foo() {
 console.log(2);  console.log(await Promise.resolve(8));  console.log(9);  }  async function bar() {  console.log(4);  console.log(await 6);  console.log(7);  }  console.log(1);  foo();  console.log(3);  bar();  console.log(5);  // 1 // 2 // 3 // 4 // 5 //8 // 9 // 6// 7 复制代码

小结:上面显示的最新修改事后的结果,按照原结果进程应该是

  • 打印1,运行foo,打印2,消息队列加入两列,打印3,运行bar,打印4,消息队列加一列进程,打印5,开始执行消息队列第一行,foo拿到返回值,bar打印6,而后打印7,回到foo第二列,打印结果8,再打印9

本文使用 mdnice 排版

相关文章
相关标签/搜索