分解一段使用了一些ES5/高级JavaScript写法的代码段?

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

谁能解释一下exports部分的部分,我好像迷路了,卡了一会儿。从 importPromise 开始。似乎有很多事情要做,例如箭头函数和 map 方法。我看不到数据从哪里流向哪里。

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()
    ]);
}

https://babeljs.io/repl

您可以使用此工具进行翻译。

涉及相当多的 ES6 魔法:)

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

importdata 是一个数组。数组上的 map 函数所做的是获取数组的每个项目并对其应用一个函数,然后 return 一个包含原始数组中所有项目但经过修改的新数组。 map function

而不是写 .map(function(item) { ... } 在 ES6 中写这个的首选方式是使用 fat arrow function,即 .map((item) => ...

魔法的第三位叫做destructuring assignment。它所做的是在这种情况下获取一个对象,并将 obj.name 和 obj.category 分配给两个新变量名称和类别。我们可以在我们的函数中使用这些变量,就像我们用两个单独的参数调用函数一样。

现在记住我们的 map 函数指示我们编写一个函数,该函数将数组项作为参数,returns 修改后的项。所以我们最终得到的是一个映射函数,它循环遍历 importData 的参数,获取每个项目的名称和类别,并用它们调用另一个函数 createPost。 createPost 的结果是项目的新值,它全部附加到一个与旧值相同大小的数组,以及修改后的项目。

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

createPost 从每个项目中创建一个承诺。您可以阅读有关 Promise here 的更多信息。 Promise 上的 .then 方法将函数作为参数;在 promise returns 时调用(成功或错误)。 () => done() 只是粗箭头语法中的一个函数,它不带参数并调用 done 函数。 .catch 也接受一个函数(done 是一个函数),并在承诺 return 出错时执行。注意。这样 done 函数在成功和错误时都会被调用!

——不,这段代码不会工作,因为我们在第一行用 importPromise 创建的实际上不是一个承诺,而是一个承诺数组!

祝你阅读顺利,正如 Beri 所建议的那样,将代码翻译成 es5 可能值得继续阅读。

我对 KeystoneJS 了解不多。无论如何,这是我的两分钱:

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

importData 是一个 Array,它包含一堆 Object 个实例,每个实例都有一个 namecategory 键以及 String值。对我来说,这似乎是一些 "mock data",只是为了测试目的而放在那里。

我移动了下一部分,因为它使代码更易于理解。

这部分:

const categories = {};

在我看来,编写它的人试图实现某种形式的 "caching"。 categories 常量仅仅是 "container" 用于存储帖子,以便以后可以重复使用它们而不是重新创建。如果您通读 createPost 函数,就会发现它的用途。

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()
    ]);
}

第一个 if 似乎是为了利用 "caching" 构造 (const category),但它的实现方式有点令人困惑。这是我重构它的方式:

const createPost = ({ name, category }) => {
    if (!categories[category]) {
        categories[category] = new PostCategory.model({ category });;
    }

    const post = new Post.model({ name });
    post.category = categories[category]._id.toString();

    return Promise.all([
        post.save(),
        categories[category].save()
    ]);
}

最后 exports 部分:

该模块导出一个等待回调的 function 作为参数 (done)。然后,它尝试通过在其上映射 createPost 函数,从模拟数据的所有 "posts" 创建一个 Promise(并且 - 据我所知 - 失败)。我认为它失败的原因是因为 Array.prototype.map 没有 return Promise,它 return 是一个新的 Array 实例,它没有 then 方法(见下一行)。与其调用 then,不如再次调用 Promise.all。当最后的 Promise 成功(或失败)时,将使用结果调用回调。

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

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

同样,我会这样重写它:

exports = function (done) {
    Promise.all(importData.map(createPost)).then(done).catch(done);
};

或者只是 return 最后的 Promise 并完全摆脱 done 回调。