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
结合起来。