[英]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.