本文详细解析JavaScript中Promise与async/await的核心作用及底层原理。通过对比传统回调地狱,阐述Promise如何通过状态传递实现解耦,并介绍async/await作为Generator语法糖如何简化异步代码编写。文章涵盖Promise的三种状态、执行器机制以及async函数的错误处理优势,帮助开发者掌握现代JS异步编程的最佳实践。
一、Promise与async/await的核心价值
这两者主要旨在解决由异步回调引发的代码复杂性问题。
Promise的字面含义为“承诺”,意指其保证会执行。可以将Promise视为一个容器,其中存放着未来才会完成的事件结果,且这些结果一旦生成便不可更改。
async和await是Generator函数的语法糖,它们内置了执行器,无需额外调用即可自动执行并输出结果,最终返回一个Promise对象。
二、Promise的具体作用
其底层实现机制如何?
Promise的核心在于状态的传递。方法的封装者无需关心异步方法的具体执行结果,而是通过状态传递获取执行结果并编写自身逻辑,从而实现封装者与使用者的真正解耦。
这种状态传递具有发布订阅模式的特征。所谓的“回调地狱”并非书写上的困难,而是因其未实现真正解耦而备受诟病。虽然Promise的链式调用也可能带来类似地狱的感觉,但async作为Promise的语法糖,旨在优化这一过程。
在Promise出现之前,处理多个异步请求时通常需要层层嵌套,前一个函数的输出作为后一个函数的输入,例如:
ajax.get(url, function(id) {
ajax.get({id}, function() {
ajax.get({name}, function() {
......
})
})
})若业务逻辑复杂,且对请求回来的数据还需进行一系列处理,此类代码对后期的可读性和维护性极不友好。而Promise的链式调用有效解决了多层异步嵌套回调的问题,显著提升了代码的可读性与可维护性。
Promise包含三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
调用new Promise时需传入一个executor执行器函数,该函数会立即执行;
executor函数接收两个参数:resolve和reject,分别对应异步请求成功和失败时的执行逻辑;
设置默认状态status为pending,请求成功时的值为value(默认undefined),请求失败时的值为reason(默认undefined)。
Promise的状态值只能从pending转换为fulfilled,或从pending转换为rejected。一旦状态确定,便不再改变。
Promise拥有一个then方法,接收两个参数onFulfilled和onRejected,分别用于处理异步请求成功和失败的回调。
三、Promise的实际应用
function getJSON() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let json = Math.random() * 2
if (json > 1) {
resolve(json)
} else {
reject(json)
}
}, 2000)
})
}
const makeRequest = () =>
getJSON()
.then(data => {
console.log('data==>', data)
return 'done'
})
.catch(err => {
console.log('err==>', err)
})
makeRequest()三、async和await的使用指南
要理解async函数,首先需了解Generator函数,因为async和await遵循的是Generator函数的语法糖。
对Generator函数(生成器)的理解:
它是ES6引入的一种数据类型,相当于一个状态机,内部封装了多种状态,同时返回一个迭代器对象。可以通过该迭代器遍历相关的值和状态。
Generator的显著特点是可以多次返回,每次的返回值作为迭代器的一部分保存下来,供我们显式调用。
- async函数是使用async关键字声明的函数。它是AsyncFunction构造函数的实例,且允许在其中使用await关键字。async和await关键字让我们能以更简洁的方式写出基于Promise的异步行为,无需刻意进行链式调用。
- async函数可能包含0个或多个await表达式。await表达式会暂停整个async函数的执行进程并出让控制权,只有当其等待的基于Promise的异步操作被兑现或被拒绝后,进程才会恢复。Promise的解决值将作为该await表达式的返回值。使用async/await关键字即可在异步代码中使用普通的try/catch代码块。
- await关键字仅在async函数内有效。若在async函数体之外使用它,将抛出语法错误SyntaxError。
- async/await的目的是简化基于Promise的API所需的语法。async/await的行为仿佛搭配使用了生成器和Promise。
- async函数必定返回一个Promise对象。如果async函数的返回值看起来不是Promise,它将被隐式地包装在一个Promise中。
四、Promise与async/await的区别
function getJSON() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let json = Math.random() * 2
if (json > 1) {
resolve(json)
} else {
reject(json)
}
}, 2000)
})
}
const makeRequest = async () => {
const value = await getJSON()
console.log(value)
return value
}
makeRequest()四、Promise与async、await的区别
- Promise是应用层的解决方案,拥有规范,不同语言均可实现,它仅能异步处理错误,在JS中本质上是一个对象。
- async-await是语言层的解决方案,可视为Promise的补充,允许用户像编写同步代码一样编写异步代码,并通过try/catch同步处理错误。
- Promise更多应用于函数封装中,而async多用于函数的使用场景。
- Promise的链式调用可能形成新的回调地狱,且无法统一处理异常。Promise本身是同步函数,多个调用不会相互等待。
- async-await通过同步写法使代码可读性更强,同时便于通过try/catch捕获异常。async-await具有明确的前后关系,可读性更佳。
到此这篇关于JavaScript Promise与async/await作用详细讲解的文章就介绍到这了,更多相关JS Promise内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!