我想知道配置模块导出的最佳方法是什么。以下示例中的“async.function”可能是FS或HTTP请求,为了示例而简化:
这是示例代码(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;
如果执行了异步回调,我该如何导出模块?
修改的 关于我的实际用例的快速说明:我正在编写一个模块来在fs.exists()回调中配置nconf(https://github.com/flatiron/nconf)(即它将解析配置文件并设置nconf)。
答案 0 :(得分:48)
您的导出无法正常工作,因为它在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;
});
您也可以使用Promise来解决这个问题。这种方法通过Promise的设计支持多次调用:
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;
});
答案 1 :(得分:10)
另一种方法是将变量包装在对象中。
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();
如果初始化程序有错误,至少你仍然得到未初始化的值而不是挂起回调。
答案 2 :(得分:10)
ES6使用承诺回答:
@IBAction func yourButtonAction(sender:UIButton)
{
isSelected = True
tableview.reloadData()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier(“YourCellIdentifier”, forIndexPath: indexPath) as! YourCell
if isSelected
{
// Set your text here
}
else
{
// Set default value
}
}
if you want to change text to previous state when user tap again on button then use.
@IBAction func yourButtonAction(sender:UIButton)
{
sender.selected = !sender.selected
isSelected = sender.selected
tableview.reloadData()
}
或者您可以直接返回Promise:
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) })
答案 3 :(得分:8)
你也可以使用Promises:
<强>一些-异步-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
请注意,promise节点创建一次,然后由节点缓存。每个require('./some-async-module')
将返回相同的对象实例(在本例中为promise实例)。
答案 4 :(得分:8)
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
};
})()
等待以后可能需要这样做:
(async function(){
var foo = await require("./theuppercode");
console.log(foo);
})();
答案 5 :(得分: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
});