代码之家  ›  专栏  ›  技术社区  ›  Trevor

如何等待蓝知更鸟承诺在多个地点定居?

  •  2
  • Trevor  · 技术社区  · 6 年前

    我有一个情况,一堆函数需要等待一个承诺的解决,因为它是init函数;

    self.init=new Promise(function(resolve){
       //do stuff, take awhile
       resolve();
    });
    

    但是,当它初始化时,异步性质意味着依赖于它作为init的其他函数正在被调用。我希望这些函数等待init完成,然后继续。

    我试着在每个函数中都这样做

    function doSomethingUseful(){
        self.init.reflect().then(function () {
           //do functions purpose
        });
    }
    function doSomethingUseless(){
        self.init.reflect().then(function () {
           //do functions purpose
        });
    }
    

    但它只能随机工作,可能只有在init已经解决的情况下才能工作,如果还没有解决,它就挂在这里,奇怪地挂起整个应用程序,尽管它是异步的。

    我正在尝试替换以前的解决方案,它涉及到间隔,并在每个函数调用中检查布尔值isInit。

    有蓝知更鸟的功能吗?或者用另一种方法来等待和检查一个承诺,看它是否得到解决?

    这个应用在很多地方都有这样的结构。通常围绕sqlite读/写。一个init来打开数据库,但是当它打开时,页面正在加载,并且它已经在尝试读/写表,所以那些读/写操作必须使用setInterval来等待,并反复检查init是否完成。

    下面是一个使用谷歌分析的例子。

    function Analytics() {
        var self = this;
        self.ready = ko.observable(false).subscribeTo('application:ready'); //attached to page ready event in jquerymobile and cordova
        self.trackerInit = new Promise(function (resolve, reject) {
            ko.computed(function () {
                if (self.ready()) {
                    window.ga.startTrackerWithId('id', 1000, resolve, reject);
                }
            });
        });
    }
    
    Analytics.prototype.trackSpeed = function (cat, interval, variable, label) {
        var self = this;
        console.log("speed tracker", cat, interval, variable, label); //this logs
        return self.trackerInit.then(function () {
            console.log("speed tracker confirm init"); //this never logs, all execution stops including other async code        
            return new Promise(function (resolve, reject) {
                window.ga.trackTiming(cat, interval, variable, label, resolve, reject);
            });
        }).catch(function (e) {
            if (e.message === "send timeout") {
                return true; //who cares about timeouts anyways
            } else {
                throw e;//rethrow it
            }
        });
    };
    

    函数在页面更改事件中调用,不返回,纯异步。调用它会导致所有执行停止。

    准备好的ko是这样做的

    self.ready = ko.observable(false).publishOn('application:ready');
    
    var deviceReady = new Promise(function (resolve) {
        $(document).on('deviceready', resolve);
    });
    var pageReady = new Promise(function (resolve) {
        $(document).on('pagecreate', resolve);
    });
    
    Promise.all([deviceReady, pageReady]).then(function () {
       //a couple of page of code and...
       self.ready(true);
    });
    

    这样更改init在检查其结果时会产生相同的挂起结果

    self.trackerInit = new Promise(function (resolve, reject) {
        console.log("initting");
        checker = setInterval(function () {
            if (window.ga) {
                console.log("ready init");
                window.ga.startTrackerWithId('id', 100, function(){
                    clearInterval(checker);
                    console.log("init complete");
                    resolve();
                }, reject);
            }
        }, 1000);
    });
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Brandon    6 年前

    它们只是承诺。只是使用 then 把他们绑起来

    function doSomethingUseful() {
      // wait for init to finish, then do our stuff
      // return the new chained promise in case someone wants to wait on us
      return self.init.then(function () {
        // do stuff
      });
    }
    
    function doSomethingUseless() {
      // wait for init to finish, then do our stuff
      // return the new chained promise in case someone wants to wait on us
      return self.init.then(function () {
        // do stuff
      });
    }
    
    
    // do both of those things and then do something else!
    Promise.all([doSomethingUseful(), doSomethingUseless()]).then(function () {
      console.log("init is done.  And we've done something useful and useless.")
    }
    

    编辑:

    基于您的附加代码,问题是如果在构建分析组件之前应用程序已经“就绪”,那么您将永远不会收到“application:ready”(因为它是在您订阅之前提供的),因此您的“就绪”可观察值将保持为假。根据邮箱文件,你需要通过 true 作为第二个论点 subscribeTo 这样,即使它发生在过去,您也会得到ready值:

    ko.observable(false).subscribeTo("application:ready", true)
    

    然而,构建所有这些可见和计算仅仅是为了实现一个承诺是过分的。怎么样:

    self.trackerInit = new Promise(function (resolve, reject) {
        const s = ko.postbox.subscribe("application:ready", function (value) {
           if (value) {
               s.dispose(); // stop listening (prevent memory leak
               window.ga.startTrackerWithId('id', 1000, resolve, reject);
           }
        }, true);
    });
    

    你甚至可以把它变成一个承诺助手:

    function whenReady(eventName) {
        return new Promise((resolve, reject) => {
            const s = ko.postbox.subscribe(eventName, value => {
                if (ready) {
                    s.dispose();
                    resolve(value);
                }
            }, true);
        });
    }
    
    function startGaTracker(id, timeout) {
        return new Promise((resolve, reject) => window.ga.startTrackerWithId(id, timeout, resolve, reject);
    }
    

    然后你可以写:

    self.trackerInit = whenReady("application:ready")
        .then(() => startGaTracker("id", 100));