zoukankan      html  css  js  c++  java
  • 异步函数封装请确保异步性(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

  • 相关阅读:
    使用MacPorts配置PHP开发环境(PHP54+PHP FPM+NGINX+MYSQL55)
    freebsd make 常用命令(非原创)
    可以通过以下步骤生成一个简单的证书:
    Javascript相关的一些碎裂的记忆
    中兴EBG2100路由器固件
    一些javascript内容
    freebsd 记事之PHP环境搭建
    vue3 中使用 vite 时的报错
    Vite2.0 按需引入Element Plus
    移动端横屏
  • 原文地址:https://www.cnblogs.com/chianquan/p/javascript.html
Copyright © 2011-2022 走看看