5 ms·
> Writing the above code example with none of the abstractions in the Getter-Setter Pyramid requires more amount of code, which is also harder to read. let
by megous 8y ago
> Writing the above code example with none of the abstractions in the Getter-Setter Pyramid requires more amount of code, which is also harder to read.
let usersRange = (start, end, result, doneCb, errorCb) => {
let xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open('GET', 'http://jsonplaceholder.typicode.com/users/' + start)
xhr.send();
xhr.onerror = ev => errorCb();
xhr.onload = ev => {
result.push(xhr.response);
if (start < end)
return usersRange(start + 1, end, result, doneCb, errorCb);
done(result);
}
};
usersRange(0, 10, [], /* completion callbacks */);
Simpler, not really harder to read (half of it is just boilerplate around XHR setup, which is abstractable away). The meat of it is onload handler.
- exceptione 8y agoShouldn't return nextUser(... be return usersRange(... ?
- megous 8y agoYes. Sorry, it was originaly all named nextUser, but I did miss that one rename.
- tracker1 8y agoNot sure, but I think an async function with fetch is easier to read. const usersRange = async (start, end) => { var result = []; for (let current = start; current < end; current++) { result.push(await fetch(`http://jsonplaceholder.typicode.com/users/${current}`).then(r => r.json()) } return result; }
- megous 8y agolet usersRange = (start, end, result, done) => { if (start == end) return done(null, result); GET('http://jsonplaceholder.typicode.com/users/' + start, res => usersRange(start + 1, end, (result.push(res), result), done), err => done(err) ) }; GET() just wraps the XHR code in my original post and provides access to onload/onerror callbacks. I used XHR, to avoid using fetch/Promise, which is part of the pyramid. I mean, I prefer async/await. The point is that it's just not inherently that much more verbose to write callback based async code. Composition would be more complicated. You'd have to use some abstract helper methods, or nest the callbacks. For example: chain( (_, next) => usersRange(0, 10, [], next), ([err, res], next) => { if (err) // blabla usersDoSomething(res), } ) vs: try { let res = await usersRange(0, 10), usersDoSomething(res), } catch(ex) { if (err) // bla bla } You can do some pretty fun stuff with functions, extending JS syntax so it has simulated goto for example: let users = [], nextUser = 0; labelledChain( (_, next) => GET('/users', next), 'got-users', ([err, res], next) => { users = res; next(); }, 'get-next-user', ([err, res], next) => { if (users[nextUser]) GET('/users/' + users[nextUser].id, next); else doneCallback(null, users); }, 'got-next-user', ([err, res], next) => { users[nextUser] = res; nextUser++; next.goto('get-next-user'); }, ) Fun challenge implementing labelledChain so that this all works. :D
- tracker1 8y agoI know it's not too bad to write callback based async... been doing it for a couple decades (first java, then flash adapters or hidden frames, then xhr). I just find if looks/feels much cleaner with async functions and promises. I have to admit, I didn't like promises and preferred node style callbacks until async/await and have been using it with babel since before the name change.
- rounce 8y ago> extending JS syntax so it has simulated goto for example JavaScript has goto, it's the `continue` statement[1]. 1: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue#Using_continue_with_a_label https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- megous 8y agoThat's not a real goto. You can only use a label for breaking out of outer loops. Useful for that, but not for other kinds of control flow control.