2013-11-27 14 views
35

私はモジュールのエクスポートを構成するための最良の方法が何であるか疑問に思っていました。以下の例では「async.functionは、」例のために簡略化FSまたはHTTPリクエスト、次のようになります。非同期nodejsモジュールのエクスポート

ここではサンプルコード(asynmodule.js)があります:

私はエクスポートすることができますどのように
var foo = "bar" 
async.function(function(response) { 
    foo = "foobar"; 
    // module.exports = foo; // having the export here breaks the app: foo is always undefined. 
}); 

// having the export here results in working code, but without the variable being set. 
module.exports = foo; 

モジュールは、非同期コールバックが実行された後にのみ使用できますか?

編集 私の実際のユースケースに簡単なメモ:私は(すなわち、それは設定ファイルを解析し、ここで、nconfを設定しますfs.exists()コールバックでnconfに(https://github.com/flatiron/nconf)を構成するモジュールを書いています)。

+0

存在しないファイルでnconf.file()が呼び出された場合、実際の使用事例で遊んでいて、nconfがうまくロードされるため、解決策は必要ありません。しかし、まだアプローチに興味があります。 – Brett

+0

私は同じ質問がある、私は約束をエクスポートすることができ、 'require'は依存関係を非同期にロードする。私はそれがバベルのフォーマッターで可能だと思います。しかし、私はこれらのための良い解決策とは思わない。 : –

答えて

33

foo宣言が内部にあるときに関数の外にあるため、エクスポートが機能しません。しかし、エクスポートを内部に置くと、モジュールを使用するときに、エクスポートが定義されているかどうかを確認することはできません。

ansyncシステムで作業する最善の方法は、コールバックを使用することです。コールバックを取得するためにコールバック代入メソッドをエクスポートし、非同期実行時に呼び出す必要があります。

例:ここでは

var foo, callback; 
async.function(function(response) { 
    foo = "foobar"; 

    if(typeof callback == 'function'){ 
     callback(foo); 
    } 
}); 

module.exports = function(cb){ 
    if(typeof foo != 'undefined'){ 
     cb(foo); // If foo is already define, I don't wait. 
    } else { 
     callback = cb; 
    } 
} 

async.functionは、非同期呼び出しを象徴するだけのプレースホルダです。メイン

var fooMod = require('./foo.js'); 
fooMod(function(foo){ 
    //Here code using foo; 
}); 

複数のコールバック方法

あなたのモジュールを使用すると、コールバックの配列を管理する必要が複数回呼び出される必要がある場合:

var foo, callbackList = []; 
async.function(function(response) { 
    foo = "foobar"; 

    // You can use all other form of array walk. 
    for(var i = 0; i < callbackList.length; i++){ 
     callbackList[i](foo) 
    } 
}); 

module.exports = function(cb){ 
    if(typeof foo != 'undefined'){ 
     cb(foo); // If foo is already define, I don't wait. 
    } else { 
     callback.push(cb); 
    } 
} 

ここasync.function非同期呼び出しを象徴するプレースホルダです。あなたはまた、それを解決するための約束を使用することができ、メイン

var fooMod = require('./foo.js'); 
fooMod(function(foo){ 
    //Here code using foo; 
}); 

約束方法

。約束の設計によるこの方法のサポート、複数のコール:ここ

var foo, callback; 
module.exports = new Promise(function(resolve, reject){ 
    async.function(function(response) { 
     foo = "foobar" 

     resolve(foo); 
    }); 
}); 

async.functionは、非同期呼び出しを象徴するだけのプレースホルダです。メイン

var fooMod = require('./foo.js').then(function(foo){ 
    //Here code using foo; 
}); 

Promise documentation

+0

ああ、意味があります。thanks Techniv – Brett

+3

2つの別々の(メイン)ファイルがfooの準備ができていないのにこの関数を呼び出すのであれば、これはうまくいきません。彼らのコールバックの1つだけが発射されます。どちらか遅い方が呼び出されます。 – laggingreflex

+0

この場合、はいです。私たちはコールバックスタックを管理しません。しかし、すべてのコールバックを格納する配列を使って解決するのは簡単です。 – Techniv

8

別のアプローチは、オブジェクト内の変数をラップされる参照します。

var Wrapper = function(){ 
    this.foo = "bar"; 
    this.init(); 
}; 
Wrapper.prototype.init = function(){ 
    var wrapper = this; 
    async.function(function(response) { 
    wrapper.foo = "foobar"; 
    }); 
} 
module.exports = new Wrapper(); 

初期化子にエラーがある場合、少なくともコールバックをハングするのではなく、初期化されていない値が残っています。

+0

これは賢いお礼です – abhilash

+3

モジュールが必要なときにどのように "foo"を取得しますか? – HelpMeStackOverflowMyOnlyHope

+0

var wrapper = require( 'wrapper'); console.log(wrapper.foo) – vangoz

7

あなたはまた、約束の利用を行うことができます。

一部-非同期module.js

module.exports = new Promise((resolve, reject) => { 
    setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000); 
}); 

main.js

var asyncModule = require('./some-async-module'); 

asyncModule.then(promisedResult => console.log(promisedResult)); 
// outputs 'someValueToBeReturned' after 2 seconds 

同じ缶別のモジュールで起こる予想通りリットルも解決:

に、いくつかの-他-module.js

var asyncModule = require('./some-async-module'); 

asyncModule.then(promisedResult => console.log(promisedResult)); 
// also outputs 'someValueToBeReturned' after 2 seconds 

注約束のオブジェクトは、それがノードでキャッシュされています一旦作成されていること。各require('./some-async-module')は、同じオブジェクトインスタンス(この場合は約束のインスタンス)を返します。

0

他の回答は部分的な回答と思われ、私にとってはうまくいかなかった。これは多少完全であると思わ:

一部-module.js

var Wrapper = function(){ 
    this.callbacks = []; 
    this.foo = null; 
    this.init(); 
}; 
Wrapper.prototype.init = function(){ 
    var wrapper = this; 
    async.function(function(response) { 
    wrapper.foo = "foobar"; 
    this.callbacks.forEach(function(callback){ 
     callback(null, wrapper.foo); 
    }); 
    }); 
} 
Wrapper.prototype.get = function(cb) { 
    if(typeof cb !== 'function') { 
     return this.connection; // this could be null so probably just throw 
    } 
    if(this.foo) { 
     return cb(null, this.foo); 
    } 
    this.callbacks.push(cb); 
} 
module.exports = new Wrapper(); 

main.js

var wrapper = require('./some-module'); 

wrapper.get(function(foo){ 
    // foo will always be defined 
}); 

main2.js

var wrapper = require('./some-module'); 

wrapper.get(function(foo){ 
    // foo will always be defined in another script 
}); 
6
const asyncFunc =() => { 
    return new Promise((resolve, reject) => { 
     // Where someAsyncFunction takes a callback, i.e. api call 
     someAsyncFunction(data => { 
      resolve(data) 
     }) 
    }) 
} 

export default asyncFunc 

... 
import asyncFunc from './asyncFunc' 
asyncFunc().then(data => { console.log(data) }) 

それとも、直接約束自体を返すことができます::

const p = new Promise(...) 
export default p 
... 
import p from './asyncModule' 
p.then(...) 
+0

これはES6と約束のための正確で現代的な答えです。これありがとう。 –

+1

質問: 'Promise'の代わりに関数を直接返す理由はありますか? 'Promise'を直接返すと、' asyncFunc.then(...) 'でアクセスすることができます。かなり新しいので、あなたの意見を求めています。 –

+1

それもうまくいくでしょう。私はこの例を書いたとき、私は非同期メソッドを持つクラスをエクスポートしていたので、それは関数のように定式化されていたと思います。しかしPromiseを次のようにエクスポートすることもできます: 'const p = new Promise(...);デフォルトのp;をエクスポートし、次にインポートモジュール 'import p from '...' p.then(...); ' – inostia

2

アンES7のアプローチはmodule.exportsはですぐに呼び出された非同期機能次のようになります。

module.exports = (async function(){ 
//some async initiallizers 
//e.g. await the db module that has the same structure like this 
    var db = await require("./db"); 
    var foo = "bar"; 

    //resolve the export promise 
    return { 
    foo 
    }; 
})() 
約束を使用してES6答え

これは、後で待つ必要があります。

(async function(){ 

    var foo = await require("./theuppercode"); 
    console.log(foo); 
})(); 
関連する問題