JavaScript Promise 与 Observables
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
JavaScript 中的异步编程
JavaScript 中有多种方法可以创建异步代码。其中最重要的几种如下:
- 回调函数
- 承诺
- 异步/等待
- RxJS Observables
回调函数
是传统的异步编程方法。你将一个函数作为参数传递给另一个执行异步任务的函数。当异步任务完成后,执行异步任务的函数会调用你的回调函数。
这种方法的主要缺点在于当存在多个链式异步任务时,你需要嵌套定义回调函数,层层嵌套,这就是所谓的“回调地狱”。
function greeting(name) {
console.log(`Hello ${name}!`);
}
function introduction(firstName, lastName, callback) {
const fullName = `${firstName} ${lastName}`;
callback(fullName);
}
introduction('Nouman','shah', greeting);
//"Hello Nouman shah!"
Promise
是在 ES6 (2015) 中引入的,目的是编写比回调函数更易读的异步代码。
回调函数和 Promise 的主要区别在于,回调函数需要你告诉执行函数在异步任务完成后应该做什么,而 Promise 则是执行函数返回一个特殊对象(Promise),然后你再告诉 Promise 在异步任务完成后应该做什么。Promise
有三种状态:
- 待处理:这是操作开始之前 Promise 的初始状态
- 已完成:这意味着指定的操作已完成。
- 操作失败:操作未完成;通常会抛出错误值。
function getUsers(onSuccess) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// Handle resolve and reject in the asynchronous API
if (onSuccess) {
resolve([
{id: 1, name: 'Jerry'},
{id: 2, name: 'Elaine'},
{id: 3, name: 'George'},
])
} else {
reject('Failed to fetch data!')
}
}, 1000)
})
}
// Run the getUsers function with the false flag to trigger an error
getUsers(false)
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
异步/等待:
有一种特殊的语法可以更方便地处理 Promise,叫做“异步/等待”。它出乎意料地容易理解和使用。
基本上,你可以将一个函数声明为异步函数,这样就可以在该函数体中使用 `await` 关键字。`await` 关键字可以放在一个求值为 Promise 的表达式前面。`await` 关键字会暂停异步函数的执行,直到 Promise 被解析。当 Promise 被解析时,整个 `await` 表达式的值会变为 Promise 的结果值,然后异步函数的执行才会恢复。
此外,异步函数本身也会返回一个 Promise,该 Promise 会在函数体执行完毕后被解析。
function asyncTask(i) {
return new Promise(resolve => resolve(i + 1));
}
async function runAsyncTasks() {
const res1 = await asyncTask(0);
const res2 = await asyncTask(res1);
const res3 = await asyncTask(res2);
return "Everything done"
}
runAsyncTasks().then(result => console.log(result));
RxJS Observables
类似于回调函数和 Promise,负责处理异步请求。Observables 是 RxJS 库的一部分,该库利用 Observables 的特性,使编写异步代码变得非常容易。
可观测物理量会经历四个阶段。它们分别是:
- 创建
- 订阅
- 执行
- 毁灭
可观察对象的创建是通过 create 函数完成的。
var observable = Rx.Observable.create((observer: any) =>{
})
要让一个可观察对象生效,我们需要订阅它。这可以通过 subscribe 方法来实现。
observable.subscribe((data)=>{
console.log(data);
})
创建代码块内部执行的是可观察对象的操作。
在发生错误或收到完整通知后,可观察对象会被销毁,并自动取消订阅。但在某些情况下,我们需要手动取消订阅。要手动执行此操作,只需使用:
var subscription = observable.subscribe(x => console.log(x)); // Later: subscription.unsubscribe();
承诺与可观察值
可观察对象是惰性的,而承诺则不是。
- Promise 具有“急切”特性:一旦创建 Promise,执行器函数就会立即被调用。
- 可观察对象是惰性的:只有当客户端订阅可观察对象时,才会调用订阅者函数。
与 Promise 不同,Observable 可以处理多个值。Promise
只能提供一个值,而 Observable 可以提供多个值。
可观察对象是可以取消的。
你可以使用 unsubscribe 方法取消订阅来取消可观察对象,而 Promise 则没有这样的功能。