Node.js的继任者Deno发布了,主页上有一个如何使用它的小演示:
import { serve } from "https://deno.land/std@0.69.0/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
req.respond({ body: "Hello World\n" });
}
当看到 for await (const req of s) 这种句式的时候不免感觉很惊讶。我们之前从来没有见过这种写法。
想象一下,当我阅读更多关于Deno的内容时,我发现这段代码实际上是有效的javascript脚本,它在Node.js中也是有效的,而我对此一无所知,这是多么令人惊讶
那么这是什么?为什么我从来没见过呢?我应该在哪里使用它?我是不是已经错过了?
如果你们有同样的问题,那很好!
这篇文章将尝试回答所有这些问题!
Iterators 迭代器
你见过这样的东西吗?
class RandomNumberGenerator {
[Symbol.iterator]() {
return {
next: () => {
return { value: Math.random() };
},
};
}
}
如果你这样做了,那么对你来说很好,你可以跳到下一节!
如果您还没有,那么让我们深入了解一下它是怎么做的:
此类 RandomNumberGenerator
实现 [Symbol.iterator]
或 @@iterator
方法(当方法通过符号属性定义时,我们引用具有双 @@
的方法)。
[Symbol.iterator]
或 @@iterator
方法在对象上定义时允许迭代对象!
由于现在我们将 @@iterator
方法定义为RandomNumberGenerator类的实例方法,因此该类的所有实例现在都是可迭代的。现在,您可以通过运行以下代码来测试它:
class RandomNumberGenerator {
[Symbol.iterator]() {
return {
next: () => {
return { value: Math.random() };
},
};
}
}
const rand = new RandomNumberGenerator();
for (const random of rand) {
console.log(random);
if (random < 0.1) break;
}
为了使一切正常工作, @@iterator
方法必须返回一个包含 next
方法的对象,并且该 next
方法需要返回另一个具有 value
和 done
属性的对象。
value
将包含返回的值,而 done
将是一个布尔值,如果设置为TRUE,则结束迭代。
虽然 value
是强制的,但可以省略 done
,如上例所示(这允许我们定义无限个迭代量)。
我们现在可以让事情变得可迭代了!
这在什么时候会变得有用呢?
我相信这在很大程度上取决于您正在创建的业务逻辑的类型。
例如,我强烈推荐的Node.js Design Patterns一书给出了一个迭代Matrix元素的示例(您可能已经将其定义为数组的数组)。
但是,如果您需要我诚实的个人意见,我还没有遇到过这样的情况:“这是迭代器的一个很好的用例”。
无论如何,让我们回到我们文章的主题:我们还需要在for循环中添加等待吗?
异步迭代器
顾名思义,异步迭代器是我们在上面的例子的异步版本。
想象一下,我们不是返回随机数字,而是返回状态。那会是什么样子?
如果我们更改上面的示例来执行此操作,它将如下所示:
const simulateDelay = (val, delay) =>
new Promise((resolve) => setTimeout(() => resolve(val), delay));
class RandomNumberGenerator {
[Symbol.asyncIterator]() {
return {
next: async () => {
return simulateDelay({ value: Math.random() }, 200); //return the value after 200ms of delay
},
};
}
}
const rand = new RandomNumberGenerator();
(async () => {
for await (const random of rand) {
console.log(random);
if (random < 0.1) break;
}
})();
有哪些变化?
- 我们首先将符号属性更改为
asyncIterator
,而不仅仅是iterator
- 我们使
next
方法成为一个异步函数。 - 我创建了simateDelay函数,该函数返回在给定时间后解析给定值的承诺。
- 我们在for循环中添加了await
- 我们将循环放在一个即时调用的函数表达式中,以避免顶级等待调用出现问题。(注意:在Node.js版本14+中不再需要此功能)
因此,我们制作了一个简单的程序,它能够迭代以异步方式获取其元素的对象。