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

相关文章
|
6月前
|
前端开发 JavaScript 开发者
前端开发中的异步编程:Promise 和 Async/Await 的比较与应用
在现代前端开发中,异步编程是不可或缺的技术。本文将深入探讨Promise和Async/Await这两种主流的异步编程方式,分析它们的优劣势及在实际项目中的应用场景。通过比较它们的语法、可读性和错误处理机制,帮助开发者更好地选择和理解如何在项目中高效地利用这些技术。
|
9天前
|
前端开发
如何使用async/await解决Promise的缺点?
总的来说,`async/await` 是对 Promise 的一种很好的补充和扩展,它为我们提供了更高效、更易读、更易维护的异步编程方式。通过合理地运用 `async/await`,我们可以更好地解决 Promise 的一些缺点,提升异步代码的质量和开发效率。
27 5
|
3月前
|
C# UED
C#一分钟浅谈:异步编程基础 (async/await)
在现代软件开发中,异步编程对于提升应用性能和响应性至关重要,尤其是在处理网络请求和文件读 异步编程允许程序在等待操作完成时继续执行其他任务,从而提高用户体验、高效利用资源,并增强并发性。在 C# 中,`async` 用于标记可能包含异步操作的方法,而 `await` 则用于等待异步操作完成。 示例代码展示了如何使用 `async` 和 `await` 下载文件而不阻塞调用线程。此外,本文还讨论了常见问题及解决方案,如不在 UI 线程上阻塞、避免同步上下文捕获以及正确处理异常。
52 0
|
4月前
|
前端开发 JavaScript 开发者
探索前端开发中的异步编程:Promise与Async/Await
在现代前端开发中,处理异步操作是至关重要的。本文将深入探讨异步编程的核心概念,重点比较JavaScript中的Promise与Async/Await两种异步编程方式。通过实例和比较,读者将能够理解这两种方法的优缺点,如何在实际开发中选择适合的异步编程模式,从而编写更简洁、可维护的代码。
|
7月前
|
前端开发
Promise 和 Async/await 在实际开发中的应用场景
Promise 和 Async/await 在实际开发中的应用场景
|
7月前
|
前端开发 JavaScript Java
Promise, async, await实现异步编程,代码详解
Promise, async, await实现异步编程,代码详解
74 1
|
7月前
|
前端开发 JavaScript
在JavaScript中,回调函数、Promise和async/await这三种异步处理机制的优缺点
JavaScript的异步处理包括回调函数、Promise和async/await。回调函数简单易懂,但可能导致回调地狱和错误处理困难。Promise通过链式调用改善了这一情况,但仍有回调函数需求和学习成本。async/await提供同步风格代码,增强可读性和错误处理,但需ES8支持,不适用于并发执行。根据项目需求选择合适机制。
|
7月前
|
前端开发 JavaScript
异步编程:由于JS是单线程执行的,所以对于耗时的操作(如网络请求),需要通过异步编程来处理。回调函数、Promise、async/await都是常用的异步编程方式。
异步编程:由于JS是单线程执行的,所以对于耗时的操作(如网络请求),需要通过异步编程来处理。回调函数、Promise、async/await都是常用的异步编程方式。
98 1
|
前端开发 JavaScript
async、await 实现原理
async、await 实现原理
82 1
C#多线程(18):一篇文章就理解async和await
C#多线程(18):一篇文章就理解async和await
262 0
C#多线程(18):一篇文章就理解async和await