如何避免Javascript中回调函数的嵌套?


大家好,请教一个问题:

如下 getItems 函数,其中 readContent 相对耗时,传入的第二个参数是success回调


 function getItems(site) {
    var ret = []; // return value
    FileUtils.readContent(site, function(result) {
        // some codes here...
        ret = arrayUnique(result);
        return ret; // ??? FIXME
    });

    return ret; // ??? FIXME
}

我希望能以如下方式获取 getItems 返回值:(返回值都是null)


 var items = getItems("test"); // ERROR: always null!!!!!

目前我能想到的一个解决办法是: getItems 同样接受一个回调函数句柄,在 readContent 的callback中调用,但是这样会导致代码中回调函数的大量嵌套

想请教的就是, getItems 能否实现阻塞,等待异步操作 readContent 返回,以确保 return ret

P.S. 我尝试过jQuery的 $.Deferred() $.when() ,由于不甚了解,所以都没有效果


 function getItems(site) {
    var ret = []; // return values
    var dfd = $.Deferred();
    var _readFn = function(dfd) {
        FileUtils.readContent(site, function(result) {
            // some codes here...
            ret = arrayUnique(result);
            dfd.resolve();
        });
        return dfd;
    };
    $.when(_readFn(dfd)).done(function() {
        return ret;
    });
}

谢谢!

jquery javascript-jquery 回调函数 JavaScript

碎月葬影233 11 years ago

因为异步嵌套在代码维护和阅读上的确存在问题, 最近花时间在寻找其解决方案. 以下是问题相关的解答.

  1. 第一段代码的返回值应该都是[]而不是null, 应该是楼主描述有问题.
  2. getItems不能实现阻塞. Javascript是单线程(不算webworkers), 如果阻塞执行某些耗时任务, 将会导致其他代码不能执行, 造成如页面UI无法响应的问题.
  3. 通过使用$.Deferred()和async这样的库和函数, 可以解决嵌套问题, 但不能完成阻塞的功能.

可以参考一下我对于js异步嵌套回调的总结 Javascript异步回调的思考及其解决方案

野生的黑白熊 answered 11 years ago

Your Answer