Callback地獄対策の2つ目はcoについてまとめました。
coはGeneratorの仕組みを利用して簡単に並列・直列処理フローを記述できるようにするライブラリです。
const co = require('co'); const thunkify = require('thunkify') // callbackを引数にとる一般的な関数 var callbackFunction = function(message, timeout, callback) { setTimeout(function() { console.log(message); callback(null, message); }, timeout); }; // thunkifyはcallbackを引数にとる関数をthunkを返却する関数に変換する // thunkにはgenerator内でyeild式を適用できる(yeildable) var thunkifiedFunction = thunkify(callbackFunction); // Promiseを返却する一般的な関数 var promiseFunction = function(message, timeout) { return new Promise(function(resolve, reject){ setTimeout(function() { console.log(message); resolve(message); }, timeout); }); }; // co関数にGenerator(function*(){...})を渡すと、 // co関数はGeneratorの処理をyeild式まで進め、 // yeild式に指定されたPromiseの完了を待ってから処理を再開させる co(function*() { console.log('--- co start ---'); // 2つの関数を並列処理する // 並列処理をするにはyeildにArrayもしくはObjectを指定する var response = yield [ thunkifiedFunction('co two', 800), promiseFunction('co one', 600), ]; console.log("response: " + JSON.stringify(response)); // 2つの関数を直列処理する yield thunkifiedFunction('co three', 200); yield promiseFunction('co four', 400); // co.wrapで定義した関数(後述)はco generator内で利用できる yield wrappedFunction(); console.log('--- co end ---'); // Generatorでreturnするとco.then()に指定した関数が実行される return "Generator finished."; // いずれかのPromiseでreject関数が呼ばれると // co.error()に指定した関数が実行される // yield Promise.reject("An error happened."); }).then(function(value){ console.log('--- then start ---'); console.log(value); }).catch((error) => { console.log('--- error start ---'); console.log(error); }); // co.wrapを使うことでco generatorを利用した関数を定義できる // この関数もPromiseを返却するのでyeildableとなる var wrappedFunction = co.wrap(function* () { console.log('--- co.wrap start ---'); var response = yield [ thunkifiedFunction('co.wrap two', 800), thunkifiedFunction('co.wrap one', 600), ]; console.log("co.wrap response: " + JSON.stringify(response)); yield thunkifiedFunction('co.wrap three', 200); yield thunkifiedFunction('co.wrap four', 400); console.log('--- co.wrap end ---'); return yield Promise.resolve(null); });
実行結果
$ node co_generator.js --- co start --- co one co two response: ["co two","co one"] co three co four --- co.wrap start --- co.wrap one co.wrap two co.wrap response: ["co.wrap two","co.wrap one"] co.wrap three co.wrap four --- co.wrap end --- --- co end --- --- then start --- Generator finished.