2010年7月30日金曜日

そのループ、InDesignのPageItemsに使っちゃだめだよ!

for (var i = 0, elem; elem = elems[i]; i++) { doSomething(elem) }って書き方見やすくていいな - JavaScriptとかPerlとかPHPとかさくらとか勉強する

上記のページで、こういう書き方が紹介されていた。
var paragraphs = document.getElementsByTagName('p');
for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) {
doSomething(paragraph);
}

へーへーへー、さっそくやってみよう、ということで。
InDesignで、てきとうに2つ3つオブジェクトを置いたドキュメントを作り
var items = app.activeDocument.pageItems;
for (var i = 0, item; item = items[i]; i++) {
$.writeln(item);
}
と、やってみた。
……無限ループ発生。

なにが起こってるのか理解できなかったので、
$.writeln(items[100])
とかやってみたら、falseもエラーも返さない。
なるほど、pageItemsとか、InDesignのコレクションはただindexで引くだけじゃ、存在してなくてもfalseを返さないのか。pageItemsだけでなくtextFramesやpathItemsでも同じ。これじゃループ抜けられないわな……。

あ、そうか、要は配列でくればいいのかな?と思い
var items = app.activeDocument.pageItems.everyItem().getElements();
for (var i = 0, item; item = items[i]; i++) {
$.writeln(item);
}
これなら上手くいく。よし。

どちらにしろpageItemsへのアクセスは遅いし、ループさせるならいったん配列にした方が無難みたいです。

2010年7月28日水曜日

InDesignでそのアイテムを持つドキュメントを得る

以外とめんどくさいんですよねこれ。再帰してparentを上がっていったり……。
と思っていたけどいい方法を思いついたのでメモ。



2010.7.29追記:時間を計ってみた。

再帰してdocumentを得る関数が、parentDoc2。
新規のドキュメントにたくさんオブジェクトを作って、このスクリプトを実行した結果、
アイテムの数 -> 644
------ parentDoc(obj) -> 171
------ parentDoc2(obj) -> 724

と、こんな感じ。グループ多めにしたけど、4倍近く速い!

2010年7月7日水曜日

ExtendScriptで、for文のiを外に出すと速いのか?

たまに、for文の中の変数(よく使うのはi)を、for文の外に出すと速くなる、と聞く。
本当かな?と思ったので試してみた。
var ary = new Array(999999);
var start,end;

//iを中で宣言、ary.lengthを変数に渡さない
start = new Date().getTime();
for(var i1=0;i1<ary.length;i1++){}; //test1
end = new Date().getTime();
$.writeln('test1 -> '+(end-start));

//iを中で宣言、ary.lengthを中で変数に渡す
start = new Date().getTime();
for(var i2=0,len2=ary.length;i2<len2;i2++){}; //test2
end = new Date().getTime();
$.writeln('test2 -> '+(end-start));

//i、ary.lengthをfor文の外で宣言
start = new Date().getTime();
var i3=0,len3=ary.length;
for(;i3<len3;i3++){}; //test3
end = new Date().getTime();
$.writeln('test3 -> '+(end-start));

結果は、
test1 -> 1293
test2 -> 726
test3 -> 730
ということになった。配列の数をfor文中の最初で変数に入れるのは明らかに効果があるけど、変数をfor文の外で宣言するのは、(少なくともExtendScriptでは)誤差の範囲内でしかなかった。

じゃあオブジェクトでforinだったらどうか?
//オブジェクトを作る
var obj = {};
var c = 'abcdefghijklmnopqrstuvwxyz'.split('');
var clen = c.length;
for(var i=0;i<99999;i++){
var key = [];
for(var ii=0;ii<10;ii++){key.push(c[Math.floor(Math.random()*clen)])};
obj[key.join('')]=i
};

var start,end;

//iを中で宣言
start = new Date().getTime();
for(var i1 in obj){}; //test1
end = new Date().getTime();
$.writeln('test1 -> '+(end-start));

//iを外で宣言
start = new Date().getTime();
var i2;
for(i2 in obj){}; //test2
end = new Date().getTime();
$.writeln('test2 -> '+(end-start));
オブジェクトを作るのにかなり時間がかかるけど気にしない。
結果は……
test1 -> 19256
test2 -> 19200
というわけで、誤差の範囲だった。