javascript - 处理相互依赖和/或分层的异步调用

标签 javascript asynchronous loose-coupling waterfall

举个例子,假设我想从某处获取文件列表,然后加载这些文件的内容,最后将它们显示给用户。在同步模型中,它将是这样的(伪代码):

var file_list = fetchFiles(source);

if (!file_list) {
    display('failed to fetch list');

} else {
        for (file in file_list) { // iteration, not enumeration
        var data = loadFile(file);

        if (!data) {
            display('failed to load: ' + file);
        } else {
            display(data);
        }
    }
}

这为用户提供了不错的反馈,如果我认为有必要,我可以将代码片段移动到函数中。生活很简单。

现在,粉碎我的梦想:fetchFiles()loadFile() 实际上是异步的。简单的出路是将它们转换为同步函数。但如果浏览器锁定等待调用完成,这就不好了。

如何处理多个相互依赖和/或分层的异步调用,而无需以经典的reductio ad spaghettum 方式深入研究无穷无尽的回调链?是否有经过验证的范例可以干净地处理这些问题,同时保持代码松散耦合?

最佳答案

Deferreds 确实是实现这一目标的方式。它们准确地捕获了您(以及大量异步代码)想要的内容:“走开去做这件可能代价高昂的事情,在此期间不要打扰我,然后在您回来时再做这件事。”

而且您不需要 jQuery 来使用它们。一个有进取心的人有ported Deferred to underscore ,并声称您甚至不需要下划线即可使用它。

所以你的代码可以是这样的:

function fetchFiles(source) {
    var dfd = _.Deferred();

    // do some kind of thing that takes a long time
    doExpensiveThingOne({
        source: source,
        complete: function(files) {
            // this informs the Deferred that it succeeded, and passes
            // `files` to all its success ("done") handlers
            dfd.resolve(files);

            // if you know how to capture an error condition, you can also
            // indicate that with dfd.reject(...)
        }
    });

    return dfd;
}

function loadFile(file) {
    // same thing!
    var dfd = _.Deferred();

    doExpensiveThingTwo({
        file: file,
        complete: function(data) {
            dfd.resolve(data);
        }
    });

    return dfd;
}

// and now glue it together
_.when(fetchFiles(source))
.done(function(files) {
    for (var file in files) {
        _.when(loadFile(file))
        .done(function(data) {
            display(data);
        })
        .fail(function() {
            display('failed to load: ' + file);
        });
    }
})
.fail(function() {
    display('failed to fetch list');
});

设置有点冗长,但是一旦您编写了处理 Deferred 状态的代码并将其塞入某处的函数中,您就不必再担心它了,您可以尝试实际流程事件很容易。例如:

var file_dfds = [];
for (var file in files) {
    file_dfds.push(loadFile(file));
}

_.when(file_dfds)
.done(function(datas) {
    // this will only run if and when ALL the files have successfully
    // loaded!
});

关于javascript - 处理相互依赖和/或分层的异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14407744/

相关文章:

javascript - 如何在基于回调的循环中使用 yield?

javascript - Reactjs es6,.map 函数不触发 onclick

javascript - 有效的 jquery/javascript 语法存在语法错误?

javascript - 如何在nodejs中异步导出模块

ios - NSURLConnection 和 sendAsynchronousRequest :queue:completionHandler: - does the completion block run in the main thread

c# - 在 F# 中正确等待返回类型为 Task<T> 的异步 C# 方法

c# - 依赖注入(inject)还是服务位置?

strong-typing - 为什么紧耦合不好但强类型好?

c# - 事件真的让代码解耦了吗?

javascript - 如何在 Azure Build Pipeline 中打包 JS 应用程序并保存在单独的 C# 存储库中