Recursion call async func with promises gets Possible Unhandled Promise Rejection - asynchronous
const PAGESIZE = 1000;
const DEFAULTLINK = `${URL}/stuff?pageSize=${PAGESIZE}&apiKey=${APIKEY}`;
export const getAllStuff = (initialLink = DEFAULTLINK) => {
let allStuff = {};
return getSuffPage(initialLink)
.then(stuff => {
allStuff = stuff;
if (stuff.next) {
return getAllStuff(stuff.next)
.then(nextStuff => {
allStuff = Object.assign({}, stuff, nextStuff);
return allStuff;
});
} else {
return allStuff;
}
});
};
const getSuffPage = nextPageLink => {
fetch(nextPageLink).then(res => {
return res.json();
});
};
Calling getAllStuff throws:
Possible Unhandled Promise Rejection (id: 0):
TypeError: Cannot read property 'then' of undefined
TypeError: Cannot read property 'then' of undefined
at getAllStuff
I think it is usually because I do not return from a promise then or something but where don't I?
I've been working with anamorphisms or unfold in JavaScript lately and I thought I might share them with you using your program as a context to learn them in
const getAllStuff = async (initUrl = '/0') =>
asyncUnfold
( async (next, done, stuff) =>
stuff.next
? next (stuff, await get (stuff.next))
: done (stuff)
, await get (initUrl)
)
const get = async (url = '') =>
fetch (url) .then (res => res.json ())
To demonstrate that this works, we introduce a fake fetch and database DB with a fake delay of 250ms per request
const fetch = (url = '') =>
Promise.resolve ({ json: () => DB[url] }) .then (delay)
const delay = (x, ms = 250) =>
new Promise (r => setTimeout (r, ms, x))
const DB =
{ '/0': { a: 1, next: '/1' }
, '/1': { b: 2, next: '/2' }
, '/2': { c: 3, d: 4, next: '/3' }
, '/3': { e: 5 }
}
Now we just run our program like this
getAllStuff () .then (console.log, console.error)
// [ { a: 1, next: '/1' }
// , { b: 2, next: '/2' }
// , { c: 3, d: 4, next: '/3' }
// , { e: 5 }
// ]
And finally, here's asyncUnfold
const asyncUnfold = async (f, init) =>
f ( async (x, acc) => [ x, ...await asyncUnfold (f, acc) ]
, async (x) => [ x ]
, init
)
Program demonstration 1
const asyncUnfold = async (f, init) =>
f ( async (x, acc) => [ x, ...await asyncUnfold (f, acc) ]
, async (x) => [ x ]
, init
)
const getAllStuff = async (initUrl = '/0') =>
asyncUnfold
( async (next, done, stuff) =>
stuff.next
? next (stuff, await get (stuff.next))
: done (stuff)
, await get (initUrl)
)
const get = async (url = '') =>
fetch (url).then (res => res.json ())
const fetch = (url = '') =>
Promise.resolve ({ json: () => DB[url] }) .then (delay)
const delay = (x, ms = 250) =>
new Promise (r => setTimeout (r, ms, x))
const DB =
{ '/0': { a: 1, next: '/1' }
, '/1': { b: 2, next: '/2' }
, '/2': { c: 3, d: 4, next: '/3' }
, '/3': { e: 5 }
}
getAllStuff () .then (console.log, console.error)
// [ { a: 1, next: '/1' }
// , { b: 2, next: '/2' }
// , { c: 3, d: 4, next: '/3' }
// , { e: 5 }
// ]
Now say you wanted to collapse the result into a single object, we could do so with a reduce – this is closer to what your original program does. Note how the next property honors the last value when a key collision happens
getAllStuff ()
.then (res => res.reduce ((x, y) => Object.assign (x, y), {}))
.then (console.log, console.error)
// { a: 1, next: '/3', b: 2, c: 3, d: 4, e: 5 }
If you're sharp, you'll see that asyncUnfold could be changed to output our object directly. I chose to output an array because the sequence of the unfold result is generally important. If you're thinking about this from a type perspective, each foldable type's fold has an isomorphic unfold.
Below we rename asyncUnfold to asyncUnfoldArray and introduce asyncUnfoldObject. Now we see that the direct result is achievable without the intermediate reduce step
const asyncUnfold = async (f, init) =>
const asyncUnfoldArray = async (f, init) =>
f ( async (x, acc) => [ x, ...await asyncUnfoldArray (f, acc) ]
, async (x) => [ x ]
, init
)
const asyncUnfoldObject = async (f, init) =>
f ( async (x, acc) => ({ ...x, ...await asyncUnfoldObject (f, acc) })
, async (x) => x
, init
)
const getAllStuff = async (initUrl = '/0') =>
asyncUnfold
asyncUnfoldObject
( async (next, done, stuff) =>
, ...
)
getAllStuff ()
.then (res => res.reduce ((x, y) => Object.assign (x, y), {}))
.then (console.log, console.error)
// { a: 1, next: '/3', b: 2, c: 3, d: 4, e: 5 }
But having functions with names like asyncUnfoldArray and asyncUnfoldObject is completely unacceptable, you'll say - and I'll agree. The entire process can be made generic by supplying a type t as an argument
const asyncUnfold = async (t, f, init) =>
f ( async (x, acc) => t.concat (t.of (x), await asyncUnfold (t, f, acc))
, async (x) => t.of (x)
, init
)
const getAllStuff = async (initUrl = '/0') =>
asyncUnfoldObject
asyncUnfold
( Object
, ...
, ...
)
getAllStuff () .then (console.log, console.error)
// { a: 1, next: '/3', b: 2, c: 3, d: 4, e: 5 }
Now if we want to build an array instead, just pass Array instead of Object
const getAllStuff = async (initUrl = '/0') =>
asyncUnfold
( Array
, ...
, ...
)
getAllStuff () .then (console.log, console.error)
// [ { a: 1, next: '/1' }
// , { b: 2, next: '/2' }
// , { c: 3, d: 4, next: '/3' }
// , { e: 5 }
// ]
Of course we have to concede JavaScript's deficiency of a functional language at this point, as it does not provide consistent interfaces for even its own native types. That's OK, they're pretty easy to add!
Array.of = x =>
[ x ]
Array.concat = (x, y) =>
[ ...x, ...y ]
Object.of = x =>
Object (x)
Object.concat = (x, y) =>
({ ...x, ...y })
Program demonstration 2
Array.of = x =>
[ x ]
Array.concat = (x, y) =>
[ ...x, ...y ]
Object.of = x =>
Object (x)
Object.concat = (x, y) =>
({ ...x, ...y })
const asyncUnfold = async (t, f, init) =>
f ( async (x, acc) => t.concat (t.of (x), await asyncUnfold (t, f, acc))
, async (x) => t.of (x)
, init
)
const getAllStuff = async (initUrl = '/0') =>
asyncUnfold
( Object // <-- change this to Array for for array result
, async (next, done, stuff) =>
stuff.next
? next (stuff, await get (stuff.next))
: done (stuff)
, await get (initUrl)
)
const get = async (url = '') =>
fetch (url).then (res => res.json ())
const fetch = (url = '') =>
Promise.resolve ({ json: () => DB[url] }) .then (delay)
const delay = (x, ms = 250) =>
new Promise (r => setTimeout (r, ms, x))
const DB =
{ '/0': { a: 1, next: '/1' }
, '/1': { b: 2, next: '/2' }
, '/2': { c: 3, d: 4, next: '/3' }
, '/3': { e: 5 }
}
getAllStuff () .then (console.log, console.error)
// { a: 1, next: '/3', b: 2, c: 3, d: 4, e: 5 }
Finally, if you're fussing about touching properties on the native Array or Object, you can skip that and instead pass a generic descriptor in directly
const getAllStuff = async (initUrl = '/0') =>
asyncUnfold
( { of: x => [ x ], concat: (x, y) => [ ...x, ...y ] }
, ...
)
getAllStuff () .then (console.log, console.error)
// [ { a: 1, next: '/1' }
// , { b: 2, next: '/2' }
// , { c: 3, d: 4, next: '/3' }
// , { e: 5 }
// ]
Related
Rust collect() chunks of a vector into Vec<Vec<bool>>
I have a vector outputs of u64 which basically only has 0s and 1s. And I want to split the vector into equal parts to get a Vec<Vec<bool>> or Vec<&[bool]]. However, somehow I can't do it it tells me 256 | .collect(); | ^^^^^^^ value of type `std::vec::Vec<std::vec::Vec<bool>>` cannot be built from `std::iter::Iterator<Item=bool>` using let sqrt_output = (outputs.len() as f64).sqrt() as usize; let output_grid: Vec<&[bool]> = outputs .chunks(sqrt_output) .map(|s| { match s { [1_u64] => true, [0_u64] => false, // this is a hack but I don't know how to return an error ... _ => true, } }) .collect();
To get back a Vec<Vec<bool>> your map closure would need to return a Vec<bool> Here's an example: fn main() { let outputs: Vec<u64> = vec![0, 1, 1, 0]; let output_grid: Vec<Vec<bool>> = outputs .chunks(2) .map(|s| { // this is an &[u64] let mut inner_vec = Vec::new(); for val in s { inner_vec.push(match val { 1 => true, 0 => false, _ => panic!("illegal number") // can just avoid push-ing if you want to ignore other numbers }) } inner_vec }) .collect(); // this prints "[[false, true], [true, false]]" println!("{:?}", output_grid) }
Ramda applySpec - keep unmodified props
Let's say I have an object const foo = { a: 1, b: 2 } and I want to add a prop c which is based on b. I could do: applySpec({ a: prop('a'), b: prop('b'), c: ({ b }) => b + 1 }, foo) and get an object like: { a: 1, b: 2, c: 3 } Is there a nicer way to do this? I've looked at evolve, assoc and applySpec but none of them seems to be fit for purpose.
You can use R.chain to create a function that apply the spec, and then merges the new object with the original one. If R.chain is used with function (f & g): chain(f, g)(x) is equivalent to f(g(x), x) In this case chain(mergeLeft, applySpec({})) is equal to mergeLeft(applySpec({}), originalObject). const { chain, mergeLeft, applySpec } = R const fn = chain(mergeLeft, applySpec({ c: ({ b }) => b + 1 })) const foo = { a: 1, b: 2 } const result = fn(foo) console.log(result) <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script> You can make this a generic function that allows adding to existing object, by using R.pipe to pass a curried R.applySpec to the chain: const { pipe, chain, mergeLeft, applySpec } = R const fn = pipe(applySpec, chain(mergeLeft)) const addCProp = fn({ c: ({ b }) => b + 1 }) const foo = { a: 1, b: 2 } const result = addCProp(foo) console.log(result) <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
How to declare functional parameters in OCaml/ReasonML?
There are two functions; funA and funB, respectively. a.i, a.o, ah, w, c are arrays in the function funA. The function funA shall be passed as a functional parameter to the function funB and the arrays should be able to be accessed by the function funB. Unfortunately, the syntax checker encountered an error "Error: Unbound record field a". Please comment, how to declare functional parameters in OCaml/ReasonML? Full list module Test = { let vector = Array.init; let matrix = (m, n, f) => vector(m, i => vector(n, f(i))); let length = Array.length; let rand = (x0, x1) => x0 +. Random.float(x1 -. x0); let funA = (ni, nh, no) => { let init = (fi, fo) => { let i = matrix(ni + 1, nh, fi); let o = matrix(nh, no, fo); (); }; let a = { let i = vector(ni + 1, _ => 1.0); let o = vector(no, _ => 1.0); (); }; let ah = vector(nh, _ => 1.0); let w = init((_, _) => rand(-0.2, 0.4), (_, _) => rand(-2.0, 4.0)); let c = init((_, _) => 0.0, (_, _) => 0.0); (); }; let funB = (net, inputs) => { let (ni, nh, no) = ( length(net.a.i), length(net.ah), length(net.a.o), ); (); }; };
To resolve the functional parameter funA which is inaccessible in the function funB, apply the following type at the beginning of the module. module Test = { type io('a) = { i: 'a, o: 'a, }; type vec = array(float); type mat = array(vec); type funA = { a: io(vec), ah: vec, w: io(mat), c: io(mat), }; .......
Reverse arguments order in curried function (ramda js)
I have a higher order function: let's say for simplicity const divideLeftToRight = x => y => x/y; I would like to have a function that performs the division but from 'right to left'. In other words, I need to have: const divideRightToLeft = x => y => y/x; I thought about doing: const divideRightToLeft = R.curry((x,y) => divideLeftToRight(y)(x)); I am wondering if there is a more elegant way to do it
You are looking for the flip function: const divideRightToLeft = R.flip(divideLeftToRight)
You could uncurry the function before flipping. (flip returns a curried function.) E.g. const divideRightToLeft = R.flip(R.uncurryN(2, divideLeftToRight)) Alternatively, you can define a custom flipCurried function: // https://github.com/gcanti/fp-ts/blob/15f4f701ed2ba6b0d306ba7b8ca9bede223b8155/src/function.ts#L127 const flipCurried = <A, B, C>(fn: (a: A) => (b: B) => C) => (b: B) => (a: A) => fn(a)(b); const divideRightToLeft = flipCurried(divideLeftToRight)
Redux / Reselect - selector reusing
I am new to selectors. I have created the following ones: import { createSelector } from 'reselect'; const getValues = (state) => state.grid; // [3, 4, 7, 3, 2, 7, 3,...] const getTiles = (state) => state.tiles; // [0, 1, 0, 1, 0, 0, 1,...] // counts selected tiles (ie. adds up all the 1s) export const getSelected = createSelector( [getTiles], tiles => tiles.reduce((acc, elem) => acc + elem, 0) ); // displays only values of selected tiles, for the rest it shows 0 export const showSelected = createSelector( [getTiles, getValues], (tiles, grid) => tiles.map((idx, i) => (idx === 1 ? grid[i] : 0)) ); export const addSelected = createSelector( [showSelected] ..... ); /* export const addSelected = createSelector( [showSelected], coun => coun.reduce((acc, elem) => acc + elem, 0) ); */ The third selector (addSelected - the last bottom, commented-out version) basically does the same thing as the first one (with different inputs). How can I make it more generic so I can reuse it instead of writing the whole 'reduce' line again?
You could just extract the reduce part into it's own function like this: import { createSelector } from 'reselect' ... // addElements adds all elements from given array const addElements = elements => elements.reduce((acc, elem) => acc + elem, 0) export const getSelected = createSelector([getTiles], addElements) export const addSelected = createSelector([showSelected], addElements) I hope this was helpful.