async函数
为了存储重要信息,据了解乌鸦在鸟巢中复制它。 这样,当一只鹰摧毁一个鸟巢时,信息不会丢失。
为了检索它自己的存储器中没有的信息,鸟巢计算机可能会询问网络中其他随机鸟巢,直到找到一个鸟巢计算机。
requestType("storage", (nest, name) => storage(nest, name));function findInStorage(nest, name) {return storage(nest, name).then(found => {if (found != null) return found;else return findInRemoteStorage(nest, name);});}function network(nest) {return Array.from(nest.state.connections.keys());}function findInRemoteStorage(nest, name) {let sources = network(nest).filter(n => n != nest.name);function next() {if (sources.length == 0) {return Promise.reject(new Error("Not found"));} else {let source = sources[Math.floor(Math.random() *sources.length)];sources = sources.filter(n => n != source);return routeRequest(nest, source, "storage", name).then(value => value != null ? value : next(),next);}}return next();}
因为connections是一个Map,Object.keys不起作用。 它有一个key方法,但是它返回一个迭代器而不是数组。 可以使用Array.from函数将迭代器(或可迭代对象)转换为数组。
即使使用Promise,这是一些相当笨拙的代码。 多个异步操作以不清晰的方式链接在一起。 我们再次需要一个递归函数(next)来建模鸟巢上的遍历。
代码实际上做的事情是完全线性的 - 在开始下一个动作之前,它总是等待先前的动作完成。 在同步编程模型中,表达会更简单。
好消息是 JavaScript 允许你编写伪同步代码。 异步函数是一种隐式返回Promise的函数,它可以在其主体中,以看起来同步的方式等待其他Promise。
我们可以像这样重写findInStorage:
async function findInStorage(nest, name) {let local = await storage(nest, name);if (local != null) return local;let sources = network(nest).filter(n => n != nest.name);while (sources.length > 0) {let source = sources[Math.floor(Math.random() *sources.length)];sources = sources.filter(n => n != source);try {let found = await routeRequest(nest, source, "storage",name);if (found != null) return found;} catch (_) {}}throw new Error("Not found");}
异步函数由function关键字之前的async标记。 方法也可以通过在名称前面编写async来做成异步的。 当调用这样的函数或方法时,它返回一个Promise。 只要主体返回了某些东西,这个Promise就解析了。 如果它抛出异常,则Promise被拒绝。
findInStorage(bigOak, "events on 2017-12-21").then(console.log);
在异步函数内部,await这个词可以放在表达式的前面,等待解Promise被解析,然后才能继续执行函数。
这样的函数不再像常规的 JavaScript 函数一样,从头到尾运行。 相反,它可以在有任何带有await的地方冻结,并在稍后恢复。
对于有意义的异步代码,这种标记通常比直接使用Promise更方便。即使你需要做一些不适合同步模型的东西,比如同时执行多个动作,也很容易将await和直接使用Promise结合起来。
