如何触发取决于 2 个(或更多)条件的 JS 事件

发布于 2024-11-18 17:50:47 字数 1194 浏览 12 评论 0原文

我正在使用 IndexedDBWeb SQLWeb 存储 在客户端上存储一些数据(或如果客户端不支持任何存储,则回退到 AJAX)。当页面加载时,我想显示商店中的一些数据。但是当 DOM 准备好时我无法显示数据,因为存储可能尚未准备好,当存储准备好时我无法显示数据,因为 DOM 可能还没有准备好。

显然,我可以实现一些条件来检查 dom 和 store 设置的标志,或者我可以使用超时,但这看起来很草率(如果需要满足两个以上的条件,则无法很好地扩展)。有没有一个普遍的“好”方法来处理这种情况?我更喜欢跨浏览器解决方案(例如 watch 不起作用)。

情况示例:

// FooServiceFactory decides which storage method to use based on
// what the browser allows and returns a new instance of the
// implementation and starts initializing resources.
var fooService = FooServiceFactory.getInstance();

// DOM is ready
window.onload = function() {

    // fooService may not be ready yet depending on whether
    // storage has already been setup or if resources need to
    // be retrieved from the server. But I don't want this calling
    // JS to know about that.
    fooService.getAllFoo(request, function(response, status) {
        // do something with response
    });
};

注意:我暂时接受了自己的答案,但仍然愿意接受更好的处理方法。

I am using IndexedDB, Web SQL or Web Storage to store some data on the client (or fallback to AJAX in the event the client doesn't support any storage). When the page loads I want to display some data from the store. But I can't display the data when the DOM is ready because the store may not be ready and I can't display the data when the store is ready because the DOM might not be ready.

Obviously I could implement some conditional that checks flags set by the dom and store or I could use a timeout but that seems sloppy (and wouldn't scale well if more than 2 conditions needed to be met). Is there a generally "good" way to handle this situation? I would prefer a cross-browser solution (E.g. watch won't work).

Example of the situation:

// FooServiceFactory decides which storage method to use based on
// what the browser allows and returns a new instance of the
// implementation and starts initializing resources.
var fooService = FooServiceFactory.getInstance();

// DOM is ready
window.onload = function() {

    // fooService may not be ready yet depending on whether
    // storage has already been setup or if resources need to
    // be retrieved from the server. But I don't want this calling
    // JS to know about that.
    fooService.getAllFoo(request, function(response, status) {
        // do something with response
    });
};

Note: I accepted my own answer for now but am still open to better ways of handling this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

偏爱你一生 2024-11-25 17:50:47

在执行相互依赖的异步操作时,我通常会使用计数器。

var running = 0;

function fire(){
  running++;

  //fire ajax bind callback

}

function callback(data){
  //do some stuff for this request
  if(--running == 0){
    //do special stuff that relies on all requests
  }
}

两个请求同时返回并且都将 if 子句评估为 true 的可能性几乎为零。

I usually go for a counter when doing asynchronous stuff that relies on each other.

var running = 0;

function fire(){
  running++;

  //fire ajax bind callback

}

function callback(data){
  //do some stuff for this request
  if(--running == 0){
    //do special stuff that relies on all requests
  }
}

The possibility of two requests coming back the same time and both evaluating the if-clause to true is almost zero.

深海少女心 2024-11-25 17:50:47

由于某些存储(Web Storage 和 IndexedDB Synchronous API)不是异步的,因此并不总是需要跟踪这一点。最好让服务实现自己处理它。

一种方法是让实现对调用进行排队并在存储准备就绪时执行它们。这对于某些客户端来说尤其重要,这将使用户在商店准备好之前“允许”商店,这可能需要无限的时间。以下是如何处理 IndexedDB 实现的示例。

var FooServiceIndexedDB = function() {
    var db = null;
    var queue = [];
    var dbRequest = window.indexedDB.open("footle", "All kinds of foo");

    var initStore = function() {
        // Misc housekeeping goes here...
        if (queue.length > 0) {
            // Things to do if there are queued functions
            for (var i = 0; i < queue.length; i++) {
                queue[i](); // Run queued function
            }
        }
    };

    dbRequest.onsuccess = function(dbRequestEvent) {
        db = dbRequestEvent.target.result;
        if (db.getVersion() != "1.0") {
            db.setVersion("1.0").onsuccess = function(versionEvent) {
                // Create stores/indexes
                initStore();
            };
        } else {
            initStore();
        }
    };

    // Public accessor
    this.getAllFoo = function(request, callback) {
        _getAllFoo(request, callback);
    };

    // Private accessor
    var _getAllFoo = function(request, callback) {
        if (db == null) {
            // This method was called before the store was ready
            queue.push(function() {_getAllFoo(request, callback);});
            return;
        }

        // Proceed getting foo
    };
};

Since some storage (Web Storage and the IndexedDB Synchronous API) are not asynchronous, there won't always be a need to keep track of this. It would be best to have the service implementation handle it by itself.

One way would be to have the implementation queue up calls and execute them when the store is ready. This would be especially important with some clients which will make the user "allow" the store before it is ready, which could take an indefinite amount of time. Here's an example of how the IndexedDB implementation could be handled.

var FooServiceIndexedDB = function() {
    var db = null;
    var queue = [];
    var dbRequest = window.indexedDB.open("footle", "All kinds of foo");

    var initStore = function() {
        // Misc housekeeping goes here...
        if (queue.length > 0) {
            // Things to do if there are queued functions
            for (var i = 0; i < queue.length; i++) {
                queue[i](); // Run queued function
            }
        }
    };

    dbRequest.onsuccess = function(dbRequestEvent) {
        db = dbRequestEvent.target.result;
        if (db.getVersion() != "1.0") {
            db.setVersion("1.0").onsuccess = function(versionEvent) {
                // Create stores/indexes
                initStore();
            };
        } else {
            initStore();
        }
    };

    // Public accessor
    this.getAllFoo = function(request, callback) {
        _getAllFoo(request, callback);
    };

    // Private accessor
    var _getAllFoo = function(request, callback) {
        if (db == null) {
            // This method was called before the store was ready
            queue.push(function() {_getAllFoo(request, callback);});
            return;
        }

        // Proceed getting foo
    };
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文