Obinwanne Hill Obinwanne Hill - 7 months ago 14
Javascript Question

How to compose an iterable function array dynamically in JavaScript

So I have the following code [that came from one of the examples on Font Face Observer Github]

var fontA = new FontFaceObserver('Family A');
var fontB = new FontFaceObserver('Family B');

Promise.all([fontA.load(), fontB.load()]).then(function () {
console.log('Family A & B have loaded');
});


I'm trying to rewrite this in such a way that I can compose the array that contains [and executes] the functions i.e.
[fontA.load(), fontB.load()]
in a dynamic manner using
push
.

Here's what I have so far.

var font_arr = ['Family A', 'Family B'];
var font_item_obj;
var font_load_item_res;
var font_load_arr = [];
for(var i = 0; i < font_arr.length; i++)
{
font_item_obj = new FontFaceObserver(font_arr[i]);
font_load_item_res = function(){
font_item_obj.load();
};
font_load_arr.push(font_load_item_res);
}

Promise.all(font_load_arr).then(function () {
console.log('Family A & B have loaded');
});


The console message is displayed, but I can't help feeling I'm doing it wrong. Also, I get a warning in WebStorm saying
Mutable variable is available from closure
where you have this code:
font_item_obj.load();


EDIT

The code needs to work on IE8 so Array's
map
method may not be viable.

UPDATE

I was able to find the answer using guidance from @SkinnyJ and @MinusFour; using the
map
function appears to work best. Here's the updated code:

var font_arr = [{'font-family': 'Family A', 'font-options': {}}, {'font-family': 'Family B', 'font-options': {}}];

function loadFont(font_obj)
{
var font_obj_family_str = font_obj['font-family'];
var font_obj_options_obj = font_obj['font-options'];

var font_load_obj = new FontFaceObserver(font_obj_family_str, font_obj_options_obj);
return font_load_obj.load();
}

Promise.all(font_arr.map(loadFont)).then(function () {
console.log('Family A & B have loaded');
});


It's quite easy to create an iterable object (in this case
font_arr
) using a
for
loop. Also, I found a shim for
map
on IE8 here
so that should solve the browser requirement.

Answer

Can you just use Array.prototype.map on an array that you dynamically create?

var fonts = [];
fonts.push('Family A');
fonts.push('Family B');

Promise.all(fonts.map(font => new FontFaceObserver(font).load()))
  .then(() => console.log('Family A & B have loaded'));