async/await获取远程环境变量的一个例子
mrdulin opened this issue · comments
上下文: 环境变量和配置文件在远程服务器上,在当前应用程序中要获取远程服务器上的配置文件,代码示范如下:
util.ts
:
async function getConfigAsync() {
console.log('getConfigAsync');
return {
meta: await 'hello'
};
}
async function setToken() {
//TODO: 获取config
console.log('setToken: ', conf);
}
async function getToken() {
//TODO: 获取config
console.log('getToken: ', conf);
}
export {setToken, getToken}
在index.ts
模块中导入并调用这两个方法:
import { setToken, getToken } from './util';
setToken();
getToken();
async function main() {
getToken();
}
main();
需求:
-
如何在
util.ts
模块中,只调用一次getConfigAsync
方法获取配置,此后在setToken
和getToken
方法被其他模块(index.ts
)调用时使用该配置变量 -
在模块作用域定义
setToken
和getToken
并导出。(意思是不要使用闭包,class,模块模式等方式导出,在其他模块直接调用setToken
和getToken
)
在演示解决方案之前,先看个一般的做法:
util-old.ts
:
function getConfig() {
console.log('getConfig');
return new Promise(resolve => {
setTimeout(() => {
resolve({ meta: 'hello' });
}, 3000);
});
}
async function setToken() {
const conf = await getConfig();
console.log('setToken: ', conf);
}
async function getToken() {
const conf = await getConfig();
console.log('getToken: ', conf);
}
export { setToken, getToken };
在index.ts
中调用,输出:
getConfig
getConfig
getConfig
setToken: { meta: 'hello' }
getToken: { meta: 'hello' }
getToken: { meta: 'hello' }
可见每一次调用setToken
或者getToken
,都会执行一次getConfig
方法获取远程配置。
解决方案:使用async/await
+ IIFE
util.ts
:
async function getConfigAsync() {
console.log('getConfigAsync');
return {
meta: await 'hello'
};
}
const config: Promise<any> = (async () => await getConfigAsync())();
async function setToken() {
const conf = await config;
console.log('setToken: ', conf);
}
async function getToken() {
const conf = await config;
console.log('getToken: ', conf);
}
export { setToken, getToken };
const config: Promise<any> = (async () => await getConfigAsync())();
这一句是重点,这样可以在util.ts
模块被import
时,立即执行getConfigAsync
获取远程配置。如果getConfigAsync
方法没有抛出异常,这时候的config
变量等价于Promise.resolve(conf)
。
const conf = await config;
等价于
const conf = await Promise.resolve({meta: 'hello'});
conf
就是{meta: 'hello'}
;
再次在index.ts
和a.ts
中调用setToken
和getToken
方法:
index.ts
:
import { setToken, getToken } from './util';
import './a';
setToken();
getToken();
async function main() {
getToken();
}
main();
a.ts
:
import { setToken, getToken } from './util';
setToken();
getToken();
输出:
getConfigAsync
setToken: { meta: 'hello' }
getToken: { meta: 'hello' }
setToken: { meta: 'hello' }
getToken: { meta: 'hello' }
getToken: { meta: 'hello' }
可见,尽管调用了多次调用了setToken
和getToken
,获取远程配置的getConfigAsync
方法,只执行了一次。
并且直接导出了在模块作用域定义的setToken
和getToken
方法,为什么特意提到这个?可以想想如果不用async/await
,而是promise
,怎么实现这个需求,并且还能直接导出定义在模块作用域的setToken
和getToken
这两个方法?
这个例子充分体现了async/await
使用同步的代码写法的优势,之前写过各种场景下的6,7个例子和promise
作对比,async/await
的优势并不是特别明显,例如如果要并发多个异步操作,使用async/await
写法是const results = await Promise.all([asyncFn1(), asyncFn2()])
,相比直接使用promise
,async/await
并没有什么显著的优势。
此外,如果在async
函数中有多个await
,异常处理很容易出现满屏try/catch
的情况,这是另外的话题了。
source code: https://github.com/mrdulin/async-await/tree/master/src/demo-7
看起来貌似只是多了一个 async 版本的 IIFE 啊...
@pbdm 更新了最后一段说明