Search code examples
javascriptecmascript-5keystonejs

Break down a code segment that uses some ES5 / advanced JavaScript methods of writing?


Can someone explain the part in the exports section, I seem to lost and stuck for a while. Starting from importPromise. It seems like there's a lot going on, such as arrow functions and map method. I can't see where the data flows from where to where.

const keystone = require('keystone');
const PostCategory = keystone.list('PostCategory');
const Post = keystone.list('Post');

const importData = [
    { name: 'A draft post', category: 'Keystone JS' },
    ...
];

exports = function (done) {
    const importPromise = importData.map(({ name, category }) => createPost({ name, category }));

    importPromise.then(() => done()).catch(done);
};

const categories = {};

const createPost = ({ name, category }) => {
    let postCategory = new PostCategory.model({ category });
    if (categories[category]) {
        postCategory = categories[category];
    }
    categories[category] = postCategory;
    const post = new Post.model({ name });
    post.category = postCategory._id.toString();
    return Promise.all([
        post.save(),
        postCategory.save()
    ]);
}

Solution

  • Quite some ES6 magic involved :)

    const importPromise = importData.map(({ name, category }) => createPost({ name, category }));
    

    importdata is an array. What the map function on an array does is to take every item of the array and apply a function to it, then return a new array with all of the items in the original array, but modified. map function

    Instead of writing .map(function(item) { ... } the preferred way of writing this in ES6 is with a fat arrow function, i.e. .map((item) => ...

    The third bit of magic is called destructuring assignment. What it does is it takes an object in this case, and assigns the obj.name and obj.category to two new variables name and category. We can use those variables within our function as if we had called the function with two separate arguments.

    Now remember our map function dictates we write a function that takes an array item as a parameter, and returns the modified item. So what we end up with is a map function looping through the arguments of importData, taking name and category of each item and calling another function createPost with them. The result of createPost is the new value of the item, and it all gets appended to an array of the same size as the old one, with the modified items.

    importPromise.then(() => done()).catch(done);
    

    createPost creates a promise out of each item. You can read more about Promise here. The .then method on a Promise takes functions as its argument; to be called when the promise returns (either with success or an error). The () => done() is simply a function in fat arrow syntax that takes no arguments and calls the done function. .catch takes a function as well (done is a function), and is executed when the promise returns an error. NB. this way the done function is called both on success and on error!

    --and no, this code won't work because what we're creating on the first line with importPromise is not actually a promise, but an array of promises!

    Good luck with reading up, and as Beri suggests it might be worthwhile translating the code to es5 to follow along.