繁体   English   中英

如何创建带有诺言的初始化函数?

[英]How to create a initialization function with promises?

我只需要为模块调用一次的初始化函数。 此函数是一个promise,由execute函数调用。 如果execute被调用两次,则第二个必须等待初始化然后继续执行。

我编写了这段代码,但是execute的第二个调用始终在等待,并且永远不会返回。 我错过了什么?

var initialized = false;
var initializing = false;
var initializationPromise;

var init = function () {
    initializing = true;
    return q.promise(function (resolve) {
        // simulate initialization
        setTimeout(function () {
            // initialized
            initialized = true;
            resolve();
        }, 1000);
    }).fin(function () {
        initializing = false;
    });
};
var execute = function () {
    return q.promise(function (resolve, reject, notify) {
        if (initialized) {
            // already initialized
            resolve();
        } else {
            if (!initializing) {
                // initializing
                initializationPromise = init().then(function () {
                    // simulate execution
                    setTimeout(function () {
                        resolve();
                    }, 1000);
                }, function (reason) {
                    reject(reason);
                });
            } else {
                // Wait : initializing in progress
                return initializationPromise;
            }
        }

    });
};

execute().then(function () {
    // This is executed
});
execute().then(function () {
    // This is never executed
});
 // Wait : initializing in progress return initializationPromise; 

是不正确的。 那什么也没有等待,它只是退出了q.promise构造函数,什么也不做。 同样,您似乎也采用了Promise构造函数antipattern

你应该做的是

var initialisationPromise = null;
function isInitialised() {
    return initialisationPromise != null && initialisationPromise.isFulfilled();
}
function isInitialising() {
    return initialisationPromise != null && initialisationPromise.isPending();
}

function init() {
    // init can be called as often as necessary, and returns when it's done
    if (initialisationPromise == null) { // do the test here!
        // this part runs only once
        initialisationPromise = q.promise(function (resolve) {
            // simulate initialization
            setTimeout(function () {
                // initialized
                resolve();
            }, 1000);
        });
    }
    return initialisationPromise;
}
function execute() {
    return init().then(function () {
        return q.promise(function(resolve, reject, notify) {
            // simulate execution
            setTimeout(function () {
                resolve();
            }, 1000);
        });
    });
}

已解决/已拒绝的诺言将保持其状态(已解决或已拒绝状态),因此您只能使用它运行一次初始化代码。 为此, init()函数应始终返回相同的承诺,而不是每次都创建它。

因此,我们在init()方法外部创建一个延迟对象( initializationDeferred ),并每次调用init()方法时使用initializationDeferred返回相同的promise 我们需要,也给检查init()已经被做过,我们使用的共享变量initializationStarted跳过setTimeout如果已经在先前的调用来完成。

现在,在execute内部,可以确保只有在init()方法时才调用then()onFulfilled回调。

 var initializationDeferred = Q.defer(); // Create here the deferred object so it's common to all init() invocations var initializationStarted = false; var init = function() { if (!initializationStarted) { initializationStarted = true; setTimeout(function() { // initialized console.log('Init timeout fired!'); initializationDeferred.resolve(true); // Resolve the promise associated to the deferred object }, 1000); } return initializationDeferred.promise; // Return the promise associated to the deferred object }; var execute = function() { return init().then(function(initialized) { // Here your module is initialized and you can do whatever you want // The value of "initialized" here is always "true" console.log('Execute: initialized?', initialized); }); }; execute().then(function() { // This is executed console.log('Execute First invocation'); }); execute().then(function() { // This is executed too console.log('Execute Second invocation'); }); 
 <script src="http://cdnjs.cloudflare.com/ajax/libs/q.js/0.9.2/q.js"></script> 

暂无
暂无

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

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