Skip to content

Instantly share code, notes, and snippets.

@jonurry
Created March 22, 2018 10:43
Show Gist options
  • Save jonurry/29fc4bf7b85d103b7842090deba86fd3 to your computer and use it in GitHub Desktop.
Save jonurry/29fc4bf7b85d103b7842090deba86fd3 to your computer and use it in GitHub Desktop.
11.1 Tracking The Scalpel (Eloquent JavaScript Solutions)
// my solution
async function locateScalpel(nest) {
let results = network(nest).map(async name => {
// if the name of the nest that was last known to hold the scalpel
// is the current nest then we have found the scalpel
// else, return null
if (name === await anyStorage(nest, name, 'scalpel')) {
return name;
} else {
return null;
}
});
// get the name of the nest that is not null
return (await Promise.all(results)).filter(nest => nest !== null)[0];
}
// official answer
async function locateScalpel(nest) {
let current = nest.name;
for (;;) {
let next = await anyStorage(nest, current, "scalpel");
if (next == current) return current;
current = next;
}
}
// my solution without async/await, just a promise
function locateScalpel2(nest) {
// recursively search nests until scalpel is found
function findScalpel(nextNest) {
// check nextNest for scalpel
return anyStorage(nest, nextNest, 'scalpel')
.then(value => {
if (value == nextNest) {
// found scalpel
return value;
} else {
// continue search from last nest known to contain scalpel
return findScalpel(value);
}
});
}
// start search at current nest
return findScalpel(nest.name);
}
// oficial answer
function locateScalpel2(nest) {
function loop(current) {
return anyStorage(nest, current, "scalpel").then(next => {
if (next == current) return current;
else return loop(next);
});
}
return loop(nest.name);
}
locateScalpel(bigOak).then(value => console.log('1st:', value));
// → Butcher Shop
locateScalpel2(bigOak).then(value => console.log('2nd:', value));
// → Butcher Shop
@jonurry
Copy link
Author

jonurry commented Mar 22, 2018

Asynchronous Programming

11.1 Tracking The Scalpel

The village crows own an old scalpel that they occasionally use on special missions—say, to cut through screen doors or packaging. To be able to quickly track it down, every time the scalpel is moved to another nest, an entry is added to the storage of both the nest that had it and the nest that took it, under the name "scalpel", with its new location as value.

This means that finding the scalpel is a matter of following the breadcrumb trail of storage entries until you find a nest where that points at the nest itself.

Write an async function locateScalpel that does this, starting at the nest on which it runs. You can use the anyStorage function defined earlier to access storage in arbitrary nests. The scalpel has been going around long enough that you may assume that every nest has a "scalpel" entry in its data storage.

Next, write the same function again without using async and await.

Do request failures properly show up as rejections of the returned promise in both versions? How?

@jonurry
Copy link
Author

jonurry commented Mar 22, 2018

Hints

This can be done with a single loop that searches through the nests, moving forward to the next when it finds a value that doesn’t match the current nest’s name and returning the name when it finds a matching value. In the async function, a regular for or while loop can be used.

To do the same in a plain function, you will have to build your loop using a recursive function. The easiest way to do this is to have that function return a promise by calling then on the promise that retrieves the storage value. Depending on whether that value matches the name of the current nest, the handler returns that value or a further promise created by calling the loop function again.

Don’t forget to start the loop by calling the recursive function once from the main function.

In the async function, rejected promises are converted to exceptions by await. When an async function throws an exception, its promise is rejected. So that works.

If you implemented the non-async function as outlined above, the way then works also automatically causes a failure to end up in the returned promise. If a request fails, the handler passed to then isn’t called, and the promise it returns is rejected with the same reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment