async函数

为了存储重要信息,据了解乌鸦在鸟巢中复制它。 这样,当一只鹰摧毁一个鸟巢时,信息不会丢失。

为了检索它自己的存储器中没有的信息,鸟巢计算机可能会询问网络中其他随机鸟巢,直到找到一个鸟巢计算机。

  1. requestType("storage", (nest, name) => storage(nest, name));
  2. function findInStorage(nest, name) {
  3. return storage(nest, name).then(found => {
  4. if (found != null) return found;
  5. else return findInRemoteStorage(nest, name);
  6. });
  7. }
  8. function network(nest) {
  9. return Array.from(nest.state.connections.keys());
  10. }
  11. function findInRemoteStorage(nest, name) {
  12. let sources = network(nest).filter(n => n != nest.name);
  13. function next() {
  14. if (sources.length == 0) {
  15. return Promise.reject(new Error("Not found"));
  16. } else {
  17. let source = sources[Math.floor(Math.random() *
  18. sources.length)];
  19. sources = sources.filter(n => n != source);
  20. return routeRequest(nest, source, "storage", name)
  21. .then(value => value != null ? value : next(),
  22. next);
  23. }
  24. }
  25. return next();
  26. }

因为connections是一个MapObject.keys不起作用。 它有一个key方法,但是它返回一个迭代器而不是数组。 可以使用Array.from函数将迭代器(或可迭代对象)转换为数组。

即使使用Promise,这是一些相当笨拙的代码。 多个异步操作以不清晰的方式链接在一起。 我们再次需要一个递归函数(next)来建模鸟巢上的遍历。

代码实际上做的事情是完全线性的 - 在开始下一个动作之前,它总是等待先前的动作完成。 在同步编程模型中,表达会更简单。

好消息是 JavaScript 允许你编写伪同步代码。 异步函数是一种隐式返回Promise的函数,它可以在其主体中,以看起来同步的方式等待其他Promise

我们可以像这样重写findInStorage

  1. async function findInStorage(nest, name) {
  2. let local = await storage(nest, name);
  3. if (local != null) return local;
  4. let sources = network(nest).filter(n => n != nest.name);
  5. while (sources.length > 0) {
  6. let source = sources[Math.floor(Math.random() *
  7. sources.length)];
  8. sources = sources.filter(n => n != source);
  9. try {
  10. let found = await routeRequest(nest, source, "storage",
  11. name);
  12. if (found != null) return found;
  13. } catch (_) {}
  14. }
  15. throw new Error("Not found");
  16. }

异步函数由function关键字之前的async标记。 方法也可以通过在名称前面编写async来做成异步的。 当调用这样的函数或方法时,它返回一个Promise。 只要主体返回了某些东西,这个Promise就解析了。 如果它抛出异常,则Promise被拒绝。

  1. findInStorage(bigOak, "events on 2017-12-21")
  2. .then(console.log);

在异步函数内部,await这个词可以放在表达式的前面,等待解Promise被解析,然后才能继续执行函数。

这样的函数不再像常规的 JavaScript 函数一样,从头到尾运行。 相反,它可以在有任何带有await的地方冻结,并在稍后恢复。

对于有意义的异步代码,这种标记通常比直接使用Promise更方便。即使你需要做一些不适合同步模型的东西,比如同时执行多个动作,也很容易将await和直接使用Promise结合起来。