Next

Next は非同期処理を簡素に記述するために作られたライブラリです。

// もっとも簡単な例
// 画像ロードが終了したらディスプレイオブジェクトに追加
N.load("image.png").then = function(loader:Loader):void {
	addChild(loader);
}

以下のような機能・特徴を持ちます

  • 新たにクラスを作らずに非同期処理を書ける
  • 非同期処理の連続実行や並列実行ができる
  • インスタンスのメソッドを逐一呼び出す方法でも、メソッドチェーンでも書ける
  • オリジナルの非同期処理を作って拡張することができる
  • 修正BSDライセンスにて提供

現在非同期処理部分に Thread を使用した Next by Thread を作成中です. ゆくゆくはこちらが trunk になる予定です.

更新履歴

09/09/09
push に関するバグを修正
AndTrigger? に空配列を渡すと次に進まないバグを修正

http://www.libspark.org/log/as3/next

導入方法

リポジトリからソースかSWCを落としてください。Next は AS3bind に依存しているのでこちらもいっしょに導入しくてください。

Next

AS3bind

基本となる書き方

import org.libspark.next.Next;
...
var next:Next = new Next();
next.非同期関数().then = function(適切な引き数):void {
	...
}

next のインスタンスから非同期処理関数を呼び出し、その後 then で関数を登録します。 非同期関数 → then の順に呼ばれ、then に登録した関数の引数にはそれまでの非同期関数の結果が渡されます。

非同期関数一覧

load(url:*, [type]:String)

Loader(画像やswf), Sound, URLLoader(テキストやバイト配列) を利用したロードを行います。

url
String か URLRequest で指定します。
type
ローダーのタイプを指定します。タイプによって結果として then や func に渡される値が変わります。タイプを省略したときは拡張子から自動判別されます。

タイプ名結果の値自動判別される拡張子
LoaderType?.LoaderLoaderswf jpg jpeg png
LoaderType?.SoundSoundmp3
LoaderType?.TextStringtxt
LoaderType?.XMLXMLxml
LoaderType?.VariablesURLVariables
LoaderType?.BinaryByteArray?
結果
type によって変わります。ロードに失敗した時や中断時は null が使用されます。

time(d:int)

一定時間待ちます

d
待ち時間を ms で指定します.
結果
なし

event(target:EventDispatcher, type:String)

イベントの発生を待ちます

target
イベントの監視対象
type
監視するイベントのタイプ
結果
発生した Event オブジェクト 中断されると null

then(f:Function)

任意の関数を実行します

f
実行する関数です。この関数には今までの処理結果が引数として渡されます
結果
f が戻り値として配列を返した場合、その要素が結果の値として使われます

func(f:Function)

任意の関数を実行します。then と違い非同期処理を開始させません

f
実行する関数です。この関数には今までの処理結果が引数として渡されます
結果
f が戻り値として配列を返した場合、その要素が結果の値として使われます

and(list:Array)

複数の Next を実行しすべてが終了するのを待ちます

list
Next の配列です
結果
すべての Next の結果をつなげた配列

or(list:Array)

複数の Next を実行しどれかが終了するのを待ちます

list
Next の配列です
結果
もっとも早く終了した Next の結果 中断時は最初の要素として登録した処理の結果

いろいろな書き方

func と then は二通りの書き方が可能です。

// 普通の書き方
next.func(function():void {
	...
});
// ブロックっぽい書き方
next.func = function():void {
	...
}

Next が使い捨てなら以下のように書けます。

(new Next).load("image.png").then = function(l:Loader) {
	...
}

さらに省略記述用にグローバル変数 N を用意してあります。 これを使用すると最初の例のように書けます。

N.load("image.png").then = function(l:Loader) {
	...
}

N なんて名前は気に食わない! という人は、グローバル変数を作ってそこに NextFactory? のインスタンスを設定すると同様の機能を実現できます。

public var NewNext:* = new NextFactory();

複数の処理を連続実行

非同期関数は自身を戻り値として返すのでメソッドチェーンの形でどんどん処理を書き足せます。非同期処理が終わると自動的に次の処理に入ります。 最後の then で今までの結果すべてを受け取ります。

// 連続して書ける
N.event(obj, "click")
 .time(5)
 .load("image.jpg")
 .then = function(clickEvent:Event, loader:Loader):void {
	...
}

メソッドチェーンは書きにくい or 読みにくいという人はローカル変数を作ってそのメソッドを逐一呼び出しても OK です。

// 連続して書ける
var next:Next = new Next();
next.event(obj, "click");
next.time(5);
next.load("image.jpg");
next.then = function(clickEvent:Event, loader:Loader):void {
	...
}

then の後に非同期処理を書き続けても問題ありません。

var next:next = new Next();
next.event(obj, "click");
next.then = function(clickEvent:Event):void {
	...
}
next.time(5);
next.load("image.jpg");
next.then = function(loader:Loader):void {
	...
}

複数の処理を並列実行

複数の Next インスタンスを使って非同期処理を並列に実行することもできます。

N.and([
	N.load("img1.jpg"),
	N.load("img2.jpg"),
	N.load("img3.jpg")
]).then = function(a:Array):void {
	// 引数は配列になる 要素は Loader
	...
}

N.or([
	N.event(buttun1, MouseEvent.CLICK),
	N.event(buttun2, MouseEvent.CLICK)
]).then = function(e:Event) {
	// 引数はいずれかの結果になる
	...
}

and, or に Next の配列を渡すと並列処理を行います。 and は指定したすべての処理が終了したとき。or はいずれかの処理が終了したときに then を呼びます。

Nextがいつ非同期処理を開始するのか

Next に登録した非同期処理は

  • then をセットしたとき
  • start() を呼んだとき
  • and や or の引数として別の Next に登録されたあとに、その Next が非同期処理を実行したとき

に開始されます。then の代わりに func を使うと非同期処理を開始せずに関数登録を行うことができます。

// ちょっぴり複雑な例
var filenameList:Array = ["img1.jpg", "img2.jpg", "img3.jpg"];
var list:Array = [];
for each(filename:String in filenameList) {
	var next:Next = N.load(filename).func = function(loader:Loader):void {
		addChild(loader);
	}
	list.push(next);
}
// 用意された Next の一括ロードを開始
N.and(list).start();

then と func 中のthis

then や func に登録した関数(以下登録関数)の中では this が「then や func を実行している Next」になります。(登録関数がバインドメソッドでない場合) 登録関数中からこの Next の非同期関数を呼び出した場合、その非同期処理は then, func の子処理となり、これが終了するまで親の then や func の処理は完了しません。

var next:Next = new Next();
next.load("image.jpg").then = function(loader:Loader):void {
	addChild(loader);
	this.time(1000);
	// ↑ next.time と書くのと同じ
}
next.event(obj, type);

next.start();

上記の例の場合 next の関数が呼ばれる順番は load -> then -> event -> time です。 が、time が 登録関数中で呼ばれているのでこれが終了するまで登録関数が終了したことになりません。 よって実際に非同期処理が実行される順番は load -> then[time] -> event となりコードに登場する順番と一致します。

func や then に登録した関数の戻り値

func や then に登録した関数が配列を返すと、その要素が func や then の結果として扱われ、 次の func や then に引数に渡されます。

N.func( function():Array {
	return [0];
}).then = function(n:int):void {
	// n==0
}

オリジナルの非同期処理

オリジナルの非同期処理として

  • ITrigger を返す関数
  • ITrigger を実装したクラス

を Next に追加できます。

function tween(target:*, params:Object):ITrigger {
    // ITrigger のシンプルな実装として Trigger がある
    var t:Trigger = new Trigger();
    params["onComplete"] = t.call;
    Tweener.addTween(target, params);
    return t;
}
Next.push(tween, sprite, {x:40, y:40, time:3});

非同期関数 tween は Trigger のインスタンスを作成し、返しています。この Trigger のメソッド call を処理終了時に呼び出すことによって Next に処理終了を通知します。call に引数を渡せばそれが結果として使われます。 非同期間数の定義後、作った関数(クラスでも可)と使用する引数を push に渡します。push は非同期処理を Next に追加するメソッドで、その他の非同期関数も裏では push をよんでいます。

執筆中 ...

Next の拡張

非同期処理として関数やクラスを作ったならば、それを Next のメソッドとして登録してしまうこともできます。登録後は他の非同期関数と同じ様に使用することができます。N からも呼べます。

Next.register("tween", tween);
N.tween(sprite, {x:40, y:40, time:3}).then = function():void {
    ...
}

処理の中止

halt メソッドを使用すると処理の中断ができます。Next に登録されたすべての処理が削除され、現在実行中の処理が中断されます。ただし、then で登録した物だけは削除されません。

var next:Next = new Next();
next.time(500).then = function():void {
   ...
}
next.halt(); // ←即座に then が実行される

また current プロパティに対して halt を行うと現在実行中の処理を中断して即座に次の処理に移ります。

var next:Next = new Next();
next.time(500).time(500).then = function():void {
   ...
}
next.current.halt(); // 最初の time が中断され次の time へ

作ったのは

[ひだちのいろ](mail:hidachinoiro@ぢーめーる)