简体   繁体   English

如何处理这些异步函数(设计模式?)

[英]How to handle these async functions (design-pattern?)

I got an application which needs to execute some booting/startup like: 我有一个应用程序,需要执行一些启动/启动,如:

  • ajax 阿贾克斯
  • dynamic requirejs 动态需求
  • routing, set up something else 路由,设置其他东西

before able to run. 在能够运行之前。

I now got difficulties organizing these tasks in a solid way together. 我现在很难以一种坚实的方式组织这些任务。 Especially the async behavior is giving me headache. 特别是异步行为让我很头疼。 Currently I am using events to share fetched results and watch the state of the application. 目前我正在使用事件来共享提取的结果并观察应用程序的状态。 Unfortunately this resulted in enological, inconvenient crap. 不幸的是,这导致了令人不快的垃圾。 Then I tried using some promises libraries like q, jquery.defered but they don't really match my problem. 然后我尝试使用一些承诺库,如q,jquery.defered,但它们并不真正符合我的问题。

This is a simplified version of the code: 这是代码的简化版本:

// this could be an ajax call fetching some user data
var fetchUser = function() {
    var user = {};
    // lets emulate the ajax call with setTimeout
    setTimeout(function() {
        // set some values
        user.username = 'bodo';
        user.password = 'helloKitty';
        // return the user object we "fetched"
        return user;
    }, 300);
};

// this could fetch some config or some requirejs modules
var fetchConfig = function() {
    var config = {};
    // we emulate this too...
    setTimeout(function() {
        return config;
    }, 200);
};

// this could be anything else like setting up some objects
var justSetUpSomething = function() {
    var someObj = {};
    someObj.router = 'this could be a router object for example';
    someObj.logger = 'or a logger';
    return someObj;
};

// in the final step everything should be merged together
// and be passed as event argument
var finalStep = function(user, config, someObj) {
    var mainObj = {};
    mainObj.user = user;
    mainObj.config = config;
    mainObj.someObj = someObj;
    // trigger some event system
    trigger('everything:ready', mainObj);
};​

Also viewable at: http://jsfiddle.net/uzJrs/3/ 也可以在http://jsfiddle.net/uzJrs/3/查看

I hope this describes my problem: 我希望这能描述我的问题:

There are three totally different, async tasks. 有三种完全不同的异步任务。 When they all a ready their results have to get merged and somehow passed to another object. 当他们都准备好了他们的结果必须合并并以某种方式传递给另一个对象。

Events make this workable but far a way from understandable and promises also don't really make me happy. 事件使这个可行,但远远不能理解,承诺也不会让我开心。 Isn't there another helpful design pattern? 是不是还有另一个有用的设计模式?

At first, as you have requirejs already there, you can use it to load your three modules. 首先,因为您已经有requirejs,您可以使用它来加载您的三个模块。 Requirejs resolves the dependencies asynchronous and in parallel, and calls the final factory function when they're loaded. Requirejs异步并行地解析依赖项,并在加载时调用最终的工厂函数。

But, also every Deferred library offers functions to merge promises: The merged one resolves when all single ones are resolved, or becomes rejected if one of them is rejected. 但是,每个Deferred库也提供合并promise的功能:合并后的一个会在所有单个解析时解析,或者如果其中一个被拒绝则被拒绝。 The respective functions are Q.all and jQuery.when : 相应的函数是Q.alljQuery.when

function fetchX() {
    var d = new $.Deferred();
    asynchronousThing(function callback(x) {
        d.resolve(x);
    });
    return d.promise();
}
$.when(fetchX(), fetchY(), …).then(function finalStep(x, y, …) {
    // merge everything together
    return new Event();
}).done(function readyCallback(e) {
    // this is effectively your 'everything:ready' "event"
});

It sounds like the majority of your functionality is actually synchronous as long as the dependencies are resolved (ie config and someObj don't do anything asynchronous they simply might be loaded asynchronously. If you are using require.js have you tried simply using its functionality to make the require calls synchronous from your code's perspective by using define ? Then you only have to worry about the call which has to be asynchronous ( fetchUser ). 听起来你的大多数功能实际上都是同步的,只要解析了依赖关系(即configsomeObj没有做任何异步,它们可能只是异步加载。如果你使用require.js,你试过简单地使用它的功能使用define从代码的角度使require调用同步?然后你只需要担心必须是异步的调用( fetchUser )。

// In app/main.js perhaps?
define(["data/user",
            "app/config",
            "app/someObject",
            "app/events"], 
    function(user, config, someObj, eventBus) {
        // By the sound of it config and someObj are ready once loaded
        var mainObj = {"config": config, "someObj": someObj};
        eventBus.register_once("data:user:loaded", function(user) {
            mainObj.user = user; 
            eventBus.trigger("everything:ready", mainObj);
        });
        user.fetchUser()
});

// in data/user.js
define(["app/config", "app/events", "vendor/jquery"],
    function(config, eventBus, $) {
        function user_loaded(user) {
            eventBus.trigger("data:user:loaded", user);
        }
        function fetchUser() {
            $.get(config.dataendpoint + "/user/1", user_loaded);
        }
    return {"fetchUser": fetchUser};
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM