[Compose] Async programming: Thunks
Thunks
Sync thunk: A blocker of code which has everything ready and can return the value directly.
function add(x, y) {
return x + y
}
const thunk = function() {
return add(10, 15)
}
thunk() // 25
Ao thunk
is pretty much the same as High order function, it can defers the result of another function call, so that you can pass thunk around to deliever the result of that function call. Notice that, the result of the function call can change over time. For example, instead of retrun add(10, 15)
, return Date.now()
. Also thunk is similar to Promise as well.
Async thunk: instead of passing params to get value back, now you passing a function, and wait it to be invoke.
function addAsync(x, y, cb) {
setTimeout(() => {
cb(x + y)
}, 1000)
}
const thunk = function(cb) {
return addAsync(10, 15, cb)
}
thunk((sum) => {
console.log(sum)
}) // 25
The power of async think is we have control over how thing is working inside thunk.
let cache = null
const thunk = function(cb) {
if (cache) {
return cache
}
cache = addAsync(10, 15, cb)
return cache
}
For example we can add cache, the first time call the thunk might take a while to do data fetching and calcaultion, but second time it return the results right away.
Which means for consumer, you might find that calling thunk multi times, it might return the data in different time durion. Aysnc thunk normalize the time, for consumer, they don't need to worry about how the callback should be invokded. It becomes time independent.
Helper method to make thunk:
function makeThunk(fn) {
var args = [].slice.call(arguments, 1)
return function(cb) {
args.push(cb)
fn.apply(null, args)
}
}
Usage:
function addAsync(x, y, cb) {
setTimeout(() => {
cb(x + y)
}, 1000)
}
const thunk = makeThunk(addAsync, 10, 15)
thunk((sum) => {
console.log(sum)
}) // 25
Coding Sync and Async thunk:
function fakeAjax(url, cb) {
var fake_responses = {
file1: "The first text",
file2: "The middle text",
file3: "The last text",
};
var randomDelay = (Math.round(Math.random() * 1e4) % 2000) + 1000;
console.log("Requesting: " + url, ", in time: ", randomDelay);
setTimeout(function () {
cb(fake_responses[url]);
}, randomDelay);
}
function output(text) {
console.log(text);
}
function getFileSync(file) {
const thunk = (cb) => {
fakeAjax(file, cb);
};
return thunk;
}
function getFileAsync(file) {
let res, fn;
fakeAjax(file, (response) => {
if (fn) {
fn(response);
} else {
res = response;
}
});
return (cb) => {
if (res) {
cb(res);
} else {
fn = cb;
}
};
}
// request all files at once in "parallel"
const th1 = getFileAsync("file1");
const th2 = getFileAsync("file2");
const th3 = getFileAsync("file3");
// request all files in sequence (concat version)
/**
const th1 = getFileSync("file1");
const th2 = getFileSync("file2");
const th3 = getFileSync("file3");
*/
th1((res1) => {
output(res1);
th2((res2) => {
output(res2);
th3((res3) => {
output(res3);
output("complete!");
});
});
});