异步函数封装请确保异步性(Javascript需要养成的良好习惯)
背景假设:
你有许多的配置信息存放在服务器上,因为配置太多,不希望每次都把所有的配置信息都写到前端,希望能需要用的时候再获取就好了。
因为Javascript单线程运行,你不希望堵塞ui渲染于是你专门写了个异步获取函数(ajax获取后台信息)
var getConfig=function(key,callback){
$.get('/config/'+key,function(config){
callback(null,config);
},'json');
};
//使用该函数
getConfig(1,function(err,config){
if(err){
return console.log(err);
}
console.log(config);
});
于是就可以欢快的使用它了。
你发现你的Javascript里面调用它的地方很多,每次都发起一个请求太费时间和资源,于是你打算给它加上缓存(为了说明问题,我们不用高阶函数:) )。
var getConfig = (function () {
var _configs = {};//缓存容器
return function (key, callback) {
if (_configs[key] === undefined) {
$.get('/config/' + key, function (config) {
_configs[key] = config;
callback(null, config);
}, 'json');
} else {
return callback(null,_configs[key]);
}
};
})();
于是你就可以欢快的使用配置了,获取过的配置都会被缓存。
问题就出在这里,你运行以下代码
getConfig('db',function(err,config){
console.log(config);//输出2
});
console.log('hello world');//输出1
在我们添加缓存之前的版本,我们每次运行该代码 都是先输出1,再输出2。但是在我们加了缓存后,假如缓存存在的话,我们的输出就变成了先输出2,再输出1,这样的情况或许在我们的事例中好像没有什么影响,但在有些情景下将会留下一些比较奇怪的bug。
这里的问题就是一个异步的不一致性问题,解决该问题可以这样。
var getConfig = (function () {
var _configs = {};//缓存容器
return function (key, callback) {
if (_configs[key] === undefined) {
$.get('/config/' + key, function (config) {
_configs[key] = config;
return callback(null, config);
}, 'json');
} else {
setTimeout(function(){//改动的地方
return callback(null,_configs[key]);
},0);
}
};
})();
我们需要把callback的运行放到下一个tick中才运行,已保持getConfig函数的异步性质。
结论:当封装函数的时候如果是一个异步函数的时候,需要确保函数的回调一直都是异步的。(这里是个新手(如我)常见的小问题,但是养成一种好的习惯,有助于保证代码的健壮性)
PS:如果你需要确保一个函数是一个异步函数,可以考虑下 async 的 async.ensureAsync方法(巧妙的运用同异步的差异实现) https://github.com/caolan/async
如果你考虑对你的方法做结果缓存,同样可以考虑 async 的 async.memoize方法(更完整,不单单缓存结果,还为高并发情况做了处理多个相同请求并发只会触发一次计算)。
ensureAsync
异步函数封装请确保异步性(Javascript需要养成的良好习惯)的更多相关文章
- callback res.end 记得return(Javascript需要养成的良好习惯)
错误示例: app.get('do',function(req,res,next){ getUserId(function(err,userId){ if(err){ res.end(err);//错 ...
- 『审慎』.Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历
异步Task简单介绍 本标题有点 哗众取宠,各位都别介意(不排除个人技术能力问题) —— 接下来:我将会用一个小Demo 把 本文思想阐述清楚. .Net 4.0 就有了 Task 函数 —— 异步编 ...
- Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历
Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历 https://www.cnblogs.com/shuxiaolong/p/DotNet_Task_BUG.html 异步Task简单 ...
- 简述异步编程&Promise&异步函数
前言:文章由本人在学习之余总结巩固思路,不足之前还请指出. 一.异步编程 首先我们先简单来回顾一下同步API和异步API的概念 1.同步API:只有当前的API执行完成之前,才会执行下一个API 例: ...
- 更优雅的方式: JavaScript 中顺序执行异步函数
火于异步 1995年,当时最流行的浏览器--网景中开始运行 JavaScript (最初称为 LiveScript). 1996年,微软发布了 JScript 兼容 JavaScript.随着网景.微 ...
- Node.js用ES6原生Promise对异步函数进行封装
Promise的概念 Promise 对象用于异步(asynchronous)计算..一个Promise对象代表着一个还未完成,但预期将来会完成的操作. Promise的几种状态: pending:初 ...
- JavaScript处理异步请求的几种方式(取异步函数返回值)
JavaScript处理异步的几种方式 Javascript语言的执行环境是"单线程"(single thread,就是指一次只能完成一件任务.如果有多个任务,就必须排队,前面一个 ...
- 获取JavaScript异步函数的返回值
今天研究一个小问题: 怎么拿到JavaScript异步函数的返回值? 1.错误尝试 当年未入行时,我的最初尝试: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <s ...
- javascript 异步请求封装成同步请求
此方法是异步请求封装成同步请求,加上token验证,环境试用微信小程序,可以修改文件中的ajax,进行封装自己的,比如用axios等 成功码采用标准的 200 到 300 和304 ,需要可以自行修改 ...
随机推荐
- Eclipse 快捷键 (应用中自己总结)
调试快捷键: 1: resume(F8) 调试中用来直接跳到下一个断点 2: 用来结束JVM 3:step into (F5)跳入函数 4: step over (F6)单步执行 5:step re ...
- window.onload和window.onscroll
之前我的一个页面里写了引入了2个js,一个是包含置顶的侧面客服,一个是定位导航.2个开始都用了window.onload,发现第一个js的定位导航没有显示,被第2个js覆盖了,当我去掉第2个js的wi ...
- Express+mysql的博客(1)
学了东西一定要自己上手试过才知道是不是真的会了.一直想练练node的使用,本来也没有什么好想法的,经同学提醒了一下,发现其实我可以用node写一个博客.我同学说工作量会非常之大╮(╯_╰)╭那也得先试 ...
- Scrum Meeting 14-20151227
说明 这几天我们代码人员一直在做数据库,没有来得及更新博客,从明天开始将会正常做scrum meeting,也将加快开发 工作,预计beta版本将会在12.30之前发布. 摘要 目前基本开发都已经做的 ...
- 妙方之解决matplotlib的图例里的中文呈现小方形
妙方之解决matplotlib的图例里的中文呈现小方形 分析思路: 每个中文都对应地呈现一个小方形, 不多也不少. 不能说是乱码. 应该是matplotlib的默认字库不支持中文造成的. 应对办法: ...
- easyx与VS2015
7.10 之前在文件头将__acrt_iob_func重定义&__iob_func,在格子涂色的程序中解决了问题:然而在俄罗斯方块的程序中出现了更多的问题,好像是FILE在其他外部依赖项cor ...
- JQuery_事件基础
JavaScript 有一个非常重要的功能,就是事件驱动.当页面完全加载后,用户通过鼠标或键盘触发页面中绑定事件的元素即可触发. jQuery 为开发者更有效率的编写事件行为, 封装了大量有益的事件方 ...
- [Jenkins] Jenkins配置自动构建时间代表意义
- htmlFormat
import java.text.SimpleDateFormat; import org.apache.log4j.HTMLLayout; import org.apache.log4j.Layou ...
- 关于malloc的一些想法
之前一段时间翻阅过一些内存分配的资料,这次终于能将其整理记录下来了. c标准库里有两个耳熟能详的函数,用于对堆空间的内存进行分配和释放,它们分别是: malloc.负责分配一个指定大小的一块内存给调用 ...