简体   繁体   English

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

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

I need a initialization function called only one time for a module. 我只需要为模块调用一次的初始化函数。 This function is a promise and is called by an execute function. 此函数是一个promise,由execute函数调用。 If execute is called twice, the second must wait the initialization then continue the execution. 如果execute被调用两次,则第二个必须等待初始化然后继续执行。

I wrote this code, but the second call of execute is always waiting and doesn't never return. 我编写了这段代码,但是execute的第二个调用始终在等待,并且永远不会返回。 What have i missed? 我错过了什么?

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; 

is not correct. 是不正确的。 That doesn't wait for anything, it just drops out of the q.promise constructor and does not do anything. 那什么也没有等待,它只是退出了q.promise构造函数,什么也不做。 Also you seem to employ the Promise constructor antipattern . 同样,您似乎也采用了Promise构造函数antipattern

What you should do instead is 你应该做的是

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);
        });
    });
}

A resolved/rejected promise will maintain its state (resolved or rejected state), so you can use it to run the initialization code only once. 已解决/已拒绝的诺言将保持其状态(已解决或已拒绝状态),因此您只能使用它运行一次初始化代码。 To do that, the init() function should return always the same promise and not create it every time. 为此, init()函数应始终返回相同的承诺,而不是每次都创建它。

For this reason, we create a deferred object ( initializationDeferred ) outside the init() method and use initializationDeferred to return the same promise every time init() method is called. 因此,我们在init()方法外部创建一个延迟对象( initializationDeferred ),并每次调用init()方法时使用initializationDeferred返回相同的promise We need, also, to check if the init() has been already done before, we use the shared variable initializationStarted to skip the setTimeout if already done in a previous invocation. 我们需要,也给检查init()已经被做过,我们使用的共享变量initializationStarted跳过setTimeout如果已经在先前的调用来完成。

Now, inside execute you can be sure that the onFulfilled callback of then() is called only when init() method is initialized. 现在,在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