用 Promise 实现 AJAX
在当今这个信息爆炸的时代,互联网就像一张无形的大网,将全世界连接在一起。作为这张大网上的一名开发者,我们常常需要从服务器拉取数据,并展示给用户。说到数据请求,就不得不提到两个名字:Ajax
和 Fetch
。这两个技术就像是互联网世界的两位老朋友和新宠儿,它们各自有着独特的能力来帮助我们获取服务器上的资源。今天我们要聊的是如何利用 Promise
来实现 Ajax
请求。
传统的 Ajax 方案
让我们先回到过去,看看 Ajax
是怎么工作的。Ajax
的全称是 Asynchronous JavaScript and XML,它并不是一个单一的技术,而是指使用 XMLHttpRequest
对象的一种编程模式,允许网页在不重新加载的情况下更新部分内容。想象一下,你正在浏览一个社交媒体网站,突然想查看最新的消息。在过去,这可能意味着整个页面都要刷新;但现在有了 Ajax
,只需要更新页面中的一部分,比如你的消息流,而不会影响到其他部分。
下面是一个简单的 Ajax
请求例子:
ini
// fetch的前辈 XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.github.com/orgs/lemoncode/members', true);
xhr.onreadystatechange = function () {
if (xhr.status == 200 && xhr.readyState == 4) {
const data = JSON.parse(xhr.responseText);
console.log(data);
}
}
xhr.send();
在这个例子中,我们创建了一个 XMLHttpRequest
实例,设置了请求的方法、URL 和是否异步(这里为 true
),然后通过 onreadystatechange
监听状态变化,当请求完成并且状态码为 200(即成功)时,处理返回的数据。
Fetch API 的登场
随着时代的发展,JavaScript 社区迎来了 Fetch
API。Fetch
是基于 Promise
的,这意味着我们可以更容易地管理异步操作。Fetch
让代码看起来更加简洁和现代化,同时也提供了更好的错误处理机制。
来看一个 Fetch
的示例:
javascript
fetch('https://jsonplaceholder.typicode.com/users')
.then(res=>res.json())
.then(data=> {
console.log(data)
})
.catch(err=>console.log(err))
在这里,我们直接调用了 fetch
方法,传入 URL。fetch
返回一个 Promise
,所以我们能够使用 .then()
来处理成功的响应,以及 .catch()
来捕捉任何可能出现的错误。是不是感觉比 Ajax
简洁多了?
使用 Promise 实现 Ajax
什么是 Promise?
Promise
是一个对象,它可以代表一个异步操作的最终完成(或失败)及其结果值。简单来说,Promise
就像是你给朋友许下的承诺------要么成功地完成了某件事情,要么因为某些原因未能完成。在 JavaScript 中,这个"承诺"一旦被做出,就不能再改变;也就是说,Promise
的状态一旦确定,就不会再变回原来的状态。
promise
专门解决异步耗时性问题,执行流程可控 其他大型语言一般是同步的,js 通过 es6promise
解决了单线程 异步不好控制的问题promise
让异步变同步 提供了完善解决异步任务的机制。
Promise 的三种状态
- Pending(等待中) :这是
Promise
初始状态,在这个时候,我们还不知道异步操作的结果。 - Fulfilled(已成功) :如果异步操作成功完成,
Promise
的状态会从pending
变为fulfilled
。这时候我们可以使用.then()
方法来获取操作的结果。 - Rejected(已失败) :相反,如果异步操作遇到了问题,
Promise
的状态会变为rejected
。我们可以使用.catch()
方法来处理这些错误。
创建和使用 Promise
当你创建一个新的 Promise
对象时,你需要提供一个执行器函数(executor),这个函数会立即执行,并接收两个参数:resolve
和 reject
。这两个函数是用来改变 Promise
状态的关键。
javascript
const myPromise = new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
const success = true;
if (success) {
resolve('Operation completed successfully!');
} else {
reject('Something went wrong.');
}
}, 1000);
});
在这个例子中,我们模拟了一个异步操作,经过一秒后决定是调用 resolve
还是 reject
函数。如果我们想要处理成功的响应,可以这样做:
javascript
myPromise.then((message) => {
console.log(message); // 'Operation completed successfully!'
});
而如果需要捕获可能发生的错误,我们可以添加一个 .catch()
:
javascript
myPromise.catch((error) => {
console.error(error); // 如果有错误发生,这里会输出错误信息
});
Promise 让异步代码更易于管理
Promise
的一大优势在于它让异步代码看起来更像是同步代码,这使得我们的程序逻辑更加清晰易懂。通过链式调用 .then()
和 .catch()
,我们可以轻松地处理多个连续的异步操作,而不需要陷入所谓的"回调地狱"。
使用 Promise 实现 Ajax
接下来,我们来构建一个使用 Promise
封装的 Ajax
函数:
javascript
// https://api.github.com/orgs/lemoncode/members url -> http (status == 200 && xreadyState == 4) -> 异步耗时任务
// -> 执行流程(DOM) -> promise
const getJson = function (url) {
return new Promise((resolve, reject) => {
// 微软推出,核心对象 XMLHttpRequest
const xhr = new XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP")
//第三个参数表示是否异步
xhr.open('GET', url, true)
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return
// 304 Not Modified
// 第一次 查找 200 后端开销
// 之后 只要后端的数据没有变化,没有必要再去查找
// 就会返回 304 状态码 不传内容
// 告诉浏览器,直接使用本地数据
if (xhr.status === 200 || xhr.status === 304) {
resolve(xhr.responseText)
} else {
reject(new Error(xhr.responseText))
}
}
xhr.send()
})
}
getJson('https://api.github.com/orgs/lemoncode/members')
.then(data=>{
console.log(JSON.parse(data))
})
.catch(error=>{
console.log(error)
})
这段代码定义了一个名为 getJson
的函数,它返回一个新的 Promise
,当请求成功时调用 resolve
,并将解析后的 JSON 数据作为参数传递;如果请求失败,则调用 reject
并提供错误信息。这样我们就有了一个可以像 Fetch
一样使用的 Ajax
函数!
arduino
const xhr = new XMLHttpRequest ? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP")
在早期的浏览器中,特别是IE浏览器,XMLHttpRequest 对象并不是标准的,因此需要使用 ActiveXObject 来创建一个类似的对象来进行AJAX请求,虽然现在不会出现这种情况,但也可能出现在面试的考点中。
总结
Promise
是 ES6 引入的一个非常重要的特性,它不仅简化了异步编程,还增强了代码的可读性和可靠性。通过理解 Promise
的工作原理以及如何正确地使用它,你可以编写出更加高效和优雅的 JavaScript 应用程序。无论是进行 API 请求还是处理复杂的用户交互,Promise
都是你不可或缺的好帮手。希望这篇文章能帮助你更好地掌握这一强大的工具!