Hexoのgeneratorプラグインで投稿記事を一つづつ処理して、新たなページを生成するプラグインを作ったときの備忘録です。

Hexoのgeneratorプラグインではlocal.postsという投稿記事が配列格納されたデータが渡ってきます。この配列をES6またはBluebirdのPromise()を使って非同期・逐次処理する例をメモしてみました。

photo by Mr. Alex Garcia - Double Cliche on flickr

hexoプラグインのサンプル

ということで、今回はhexoで記事に応じたページ/パーマリンク/generate-sample/index.htmlを新たに生成するプラグインを想定し、サンプルコードを書いてみたいと思います。

前述の通り、Hexoのgeneratorプラグインではlocal.postsという投稿記事が配列格納されたデータが渡ってきます。これをPromiseで処理する為に以下のような形で書いてみました。

index.js
1
hexo.extend.generator.register('sample', require('./lib/generator'));
./lib/generator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
'use strict';

var Promise = require('bluebird');
var assign = require('object-assign');
var pathFn = require('path');
var sequence = Promise.resolve();

module.exports = function(locals) {
var config = this.config;

// D1 : ここにtempDataを配置するとオブジェクトの値が保持される
var tempData = { "count" : 0};
return Promise.all( locals.posts.map(function(post){
// D2 : ここにtempDataを配置するとオブジェクトの値を毎度 初期化できる
// var tempData = { "count" : 0};
return {
path : pathFn.join( post.path , "generate-sample/index.html" ) ,
data : "<html>sample HTML</html>" ,
no : tempData
}
}))
.then(localPostsProcess)
.then(finish_return);
};

// Processing upon completion
function finish_return(results){
console.log("finish! " + results.length );
return results;
}

// Processing on local.posts
function localPostsProcess(results){
return new Promise.all( results.map(postProcess));
}

// Processing on post
function postProcess(result){

// P1: 非同期で実行
return filterA(result)
.then(filterB)

// // P2: 逐次実行 (promiseブロッキング)
// return sequence = sequence
// .then(function () {
// return result
// })
// .then(filterA)
// .then(filterB)
}


function filterA(result){
return new Promise(function(resolve , reject){
setTimeout(function(){
var update_result = assign(
result ,
{
"no" : assign( result.no , {"count" : result.no.count + 1 } )
}
);

console.log("A-" + String(update_result.no.count));
resolve(update_result)
},2000);
})
}

function filterB(result){
return new Promise(function(resolve , reject){
setTimeout(function(){
console.log("B-" + String(result.no.count));
resolve(result)
},1000);
})
}

コメントのD1,D2、またP1、P2を使い分ける事で、処理の流れや値の扱い方が変わります。Promiseブロッキングは以下のサイトが参考になりました。

trumpのメモ
forEach内でpromiseによる逐次処理