核心要点
ECMAScript 6(又名 ECMAScript 2015 或 ES6)为 JavaScript 带来了许多新特性,使其成为大型应用程序的理想选择。其中一项特性是使用 Promise 和 Generator 更好地支持异步编程。另一项是增加了 Fetch API,旨在取代 XMLHttpRequest 成为与远程资源通信的基础。
Fetch API 的方法返回 ES6 Promise 对象,这些对象可以与 Generator 结合使用,构成复杂异步操作的基础。这可以是任何东西,从一系列异步操作(其中每个操作都依赖于前一个操作返回的值)到必须重复向服务器发出异步调用以获取最新更新的操作。
在本文中,我们将了解如何将 Fetch API 与 Generator 结合使用来构建异步 API。Fetch API 目前受 Chrome、Opera、Firefox 和 Android 浏览器支持。对于不受支持的浏览器,我们提供了一个来自 GitHub 的 polyfill。
与往常一样,本文的代码可以在我们的 GitHub 存储库中找到,文章底部有一个最终技术的演示。
使用 Generator 进行异步操作
提示:如果您需要复习 Generator 的内容及其工作方式,请查看:ECMAScript 2015:Generator 和迭代器
那么,我们如何使用 Generator 执行异步操作呢?好吧,如果我们分析 Generator 的工作方式,我们就会找到答案。
实现迭代器的 Generator 函数具有以下结构:
function *myIterator(){ while(condition){ //计算要返回的下一个值 yield value; } }
yield
关键字负责返回结果并暂停迭代器函数的执行,直到下次调用它为止。它还保留函数的状态,而不是在下次调用时重新运行所有内容,有效地记住它上次离开的地方。
我们可以将上述函数重新设想为没有 while
循环的形式:
function *myIterator(){ while(condition){ //计算要返回的下一个值 yield value; } }
在上述两种情况下,函数的行为是相同的。使用 yield
关键字的唯一原因是暂停函数的执行,直到下一次迭代(这本身似乎有点异步)。由于 yield
语句可以返回任何值,我们也可以返回 Promise 并使函数运行多个异步调用。
将 Generator 与 Fetch API 结合使用
提示:有关 Fetch API 的复习,请查看:Fetch API 简介
如前所述,Fetch API 旨在取代 XMLHttpRequest。这个新的 API 提供了对 HTTP 请求各个部分的控制,并返回一个 Promise,该 Promise 根据服务器的响应而解析或拒绝。
Fetch API 和 Generator 可以一起使用的用例之一是长轮询。长轮询是一种技术,其中客户端不断向服务器发送请求,直到获得响应。在这种情况下,可以使用 Generator 不断产出响应,直到响应包含数据为止。
为了模拟长轮询,我在示例代码中包含了一个 Express REST API,该 API 在五次尝试后响应城市的实时天气信息。以下是 REST API:
function *myIterator(){ //计算值 1 yield value1; //计算值 2 yield value2; ... //计算值 n yield valuen; }
现在,让我们编写一个 Generator 函数,该函数多次调用此 API 并在每次迭代时返回一个 Promise。在客户端,我们不知道在多少次迭代后我们将从服务器获取数据。因此,此方法将具有一个无限循环,每次迭代都会 ping 服务器并在每次迭代时返回 Promise。以下是此方法的实现:
var polls=0; app.get('/api/currentWeather', function(request, response){ console.log(polls, polls < 5); if(polls < 5){ polls++; response.send({}); } else { response.send({temperature: 25}); } });
我们需要一个函数来不断调用此函数并检查 Promise 解析后值是否存在。它将是一个递归函数,调用 Generator 的下一次迭代,并且只有在找到从 Generator 返回的值时才会停止该过程。以下代码片段显示了此方法的实现以及调用此方法的语句:
function *pollForWeatherInfo(){ while(true){ yield fetch('/api/currentWeather',{ method: 'get' }).then(function(d){ var json = d.json(); return json; }); } }
正如我们在这里看到的,对函数 runPolling
的第一次调用创建了 Generator 对象。next
方法返回一个带有 value
属性的对象,在我们的例子中,它包含 fetch
方法返回的 Promise。当此 Promise 解析时,它将包含一个空对象(如果 polls
变量小于 5 则返回),或包含所需信息的另一个对象。
接下来,我们检查此对象的 temperature
属性(这将表示成功)。如果它不存在,我们将 Generator 对象传递回下一个函数调用(以免丢失 Generator 的状态),或者我们将对象的值打印到控制台。
要查看它的实际效果,请从我们的存储库中获取代码,安装依赖项,启动服务器,然后导航到 https://www.php.cn/link/494ad0d24e15c7da81c7ea265c7f4cb4 shell 中看到以下结果:
0 true sending...empty 1 true sending...empty 2 true sending...empty 3 true sending...empty 4 true sending...empty 5 false sending...object
以及打印到浏览器控制台的对象本身。
通常,我们需要实现多个依赖的异步调用,其中每个后续异步操作都依赖于前一个异步操作返回的值。如果我们有一组这样的操作并且它们必须多次调用,我们可以将它们放在一个 Generator 函数中并在需要时执行它。
为了演示这一点,我将使用 GitHub 的 API。此 API 使我们可以访问有关用户、组织和存储库的基本信息。我们将使用此 API 获取对组织的随机存储库的贡献者列表并在屏幕上显示获取的数据。
为此,我们需要调用三个不同的端点。以下是需要执行的任务:
让我们创建一个围绕 Fetch API 的包装函数,以避免重复编写代码来创建标头和构建请求对象。
function *myIterator(){ while(condition){ //计算要返回的下一个值 yield value; } }
以下函数使用上述函数并在每次调用时产生一个 Promise:
function *myIterator(){ //计算值 1 yield value1; //计算值 2 yield value2; ... //计算值 n yield valuen; }
现在,让我们编写一段逻辑来调用上述函数以获取 Generator,然后使用从服务器获得的值来填充 UI。由于对 Generator 的 next
方法的每次调用都会返回一个 Promise,我们将不得不链接这些 Promise。以下是使用上述函数返回的 Generator 的代码框架:
var polls=0; app.get('/api/currentWeather', function(request, response){ console.log(polls, polls < 5); if(polls < 5){ polls++; response.send({}); } else { response.send({temperature: 25}); } });
(此处省略了Demo部分,因为无法在Markdown中呈现CodePen)
结论
在本文中,我演示了如何将 Fetch API 与 Generator 结合使用来构建异步 API。ECMAScript 6 将为该语言带来大量新特性,寻找创造性的方法来组合它们并利用它们的力量通常会带来出色的结果。但你怎么看?这是我们可以立即在我们的应用程序中开始使用的一种技术吗?我很想在评论中听到您的想法。
(此处省略了FAQ部分,因为内容与前面已有的信息高度重复)
以上是使用FETCH API和ES6发电机的异步API的详细内容。更多信息请关注PHP中文网其他相关文章!