async和await是如何实现异步编程?

简介:

async和await是如何实现异步编程?
目录

异步编程样例
样例解析
浅谈Promise如何实现异步执行
参考

1.异步编程样例

样例:

// 等待执行函数
function sleep(timeout) {
return new Promise((resolve) => {

setTimeout(resolve, timeout)

})
}

// 异步函数
async function test() {
console.log('test start')
await sleep(1000)
console.log('test end')
}

console.log('start')
test()
console.log('end')
执行结果:

start
test start
end
test end

2.样例解析

在样例代码中,test异步函数使用了async和await语法,这是ES2017里面的异步编程规范。而为了在较低版本的浏览器或Node支持这种语法,其中一种解决方案是将其转化为Generator函数和Promise来实现。换句话说,任何的async和await实现的异步函数,都可以替换成Generator函数和Promise实现。

第一步:先将async和await语法替换为相应的Generator 函数,如下

// 代码结构完全一致,只是替换了对应关键字
function *test() {
console.log('test start')
yield sleep(1000)
console.log('test end')
}
第二步:为了执行Generator 函数,使用Promise实现一个自动执行器函数 spawn

function spawn(genF) {
return new Promise(function(resolve, reject) {

const gen = genF();
function step(nextF) {
  let next;
  try {
    next = nextF();
  } catch(e) {
    return reject(e);
  }
  if(next.done) {
    return resolve(next.value);
  }
  Promise.resolve(next.value).then(function(v) {
    step(function() { return gen.next(v); });
  }, function(e) {
    step(function() { return gen.throw(e); });
  });
}
step(function() { return gen.next(undefined); });

});
}
第三步:将相应的Generator 函数和自动执行器函数相结合,即可得最终的等价代码

function asyncTest() {
spawn(test)
}

console.log('start')
asyncTest()
console.log('end')
第四步:执行结果,与原来的一致

start
test start
end
test end
第五步:分析asyncTest函数执行过程

执行到 spawn(test),进入spawn函数中,创建一个Promise并返回。
执行到const gen = genF(),获取一个状态机。(Generator 函数是一个状态机,封装了多个内部状态。)
执行到 step(function() { return gen.next(undefined); }), 进入step 函数中。
执行到next = nextF() ,next等于gen.next(undefined)的返回结果。
当gen.next(undefined)开始执行,状态机第一次调用,直到遇到第一个yield表达式为止,即yield sleep(1000),此时控制台先输出"test start",并且返回第一个状态{ value: reuslt, done: false }, 而 reuslt等于sleep(1000)返回的结果,其是一个Promise。
执行到if(next.done) ,此时第一个状态的done为false,所以不执行if语句里面,继续往下执行。
执行到Promise.resolve(next.value),由于第一个状态的value是一个Promise,所以直接返回其本身,也就相当于执行sleep(1000).then(...),sleep函数异步等待1秒后,resolve接受的值为undefined,继续执行then方法。
执行到 step(function() { return gen.next(v); }),此时v为undefined,再次进入step 函数中。
再次执行到next = nextF() ,next等于gen.next(undefined)的返回结果。
当gen.next(undefined)再次执行时,状态机第二次调用,此时Generator函数已经执行完毕,此时控制台先输出"test end",并且返回最后的状态{ value: undefined, done: true }
执行到if(next.done) ,此时第一个状态的done为true,所以执行if语句里面。
执行到return resolve(next.value),此时最初的Promise成功执行。
至此asyncTest函数执行结束。

3.浅谈Promise如何实现异步执行

从上述样例解析中可以看出,我们是用Promise来实现代码的异步执行,那Promise的内部是如何实现异步执行的呢?

通过查看Promise的源码实现,发现其异步执行是通过asap这个库来实现的。

asap是as soon as possible的简称,在Node和浏览器环境下,能将回调函数以高优先级任务来执行(下一个事件循环之前),即把任务放在微任务队列中执行。

宏任务(macro-task)和微任务(micro-task)表示异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。

用法:

asap(function () {

// ...

});

4.参考

ECMAScript 6 入门 - async 函数

【翻译】Promises/A+规范

Promise - Bare bones Promises/A+ implementation

原文地址https://www.cnblogs.com/forcheng/p/12668387.html

相关文章
|
4天前
|
前端开发 JavaScript 开发者
前端开发中的异步编程:Promise 和 Async/Await 的比较与应用
在现代前端开发中,异步编程是不可或缺的技术。本文将深入探讨Promise和Async/Await这两种主流的异步编程方式,分析它们的优劣势及在实际项目中的应用场景。通过比较它们的语法、可读性和错误处理机制,帮助开发者更好地选择和理解如何在项目中高效地利用这些技术。
|
2月前
|
前端开发
async和await 优雅处理异步
async和await 优雅处理异步
|
2月前
|
前端开发
Await和Async是什么?跟Promise有什么区别 使用它有什么好处
Await和Async是什么?跟Promise有什么区别 使用它有什么好处
|
2月前
|
前端开发
Promise 和 Async/await 在实际开发中的应用场景
Promise 和 Async/await 在实际开发中的应用场景
|
2月前
|
前端开发 JavaScript
在JavaScript中,回调函数、Promise和async/await这三种异步处理机制的优缺点
JavaScript的异步处理包括回调函数、Promise和async/await。回调函数简单易懂,但可能导致回调地狱和错误处理困难。Promise通过链式调用改善了这一情况,但仍有回调函数需求和学习成本。async/await提供同步风格代码,增强可读性和错误处理,但需ES8支持,不适用于并发执行。根据项目需求选择合适机制。
|
2月前
|
前端开发 JavaScript Java
Promise, async, await实现异步编程,代码详解
Promise, async, await实现异步编程,代码详解
32 1
|
2月前
|
前端开发 JavaScript 编译器
深入解析JavaScript中的异步编程:Promises与async/await的使用与原理
【4月更文挑战第22天】本文深入解析JavaScript异步编程,重点讨论Promises和async/await。Promises用于管理异步操作,有pending、fulfilled和rejected三种状态。通过.then()和.catch()处理结果,但可能导致回调地狱。async/await是ES2017的语法糖,使异步编程更直观,类似同步代码,通过事件循环和微任务队列实现。两者各有优势,适用于不同场景,能有效提升代码可读性和维护性。
|
2月前
|
监控 前端开发 JavaScript
等一下!深入async/await的异步世界
等一下!深入async/await的异步世界
59 1
|
2月前
|
前端开发 JavaScript
异步编程:由于JS是单线程执行的,所以对于耗时的操作(如网络请求),需要通过异步编程来处理。回调函数、Promise、async/await都是常用的异步编程方式。
异步编程:由于JS是单线程执行的,所以对于耗时的操作(如网络请求),需要通过异步编程来处理。回调函数、Promise、async/await都是常用的异步编程方式。
66 1
|
11月前
|
前端开发 JavaScript
async、await 实现原理
async、await 实现原理
57 1