如何创建带有承诺的初始化函数?
How to create a initialization function with promises?
我需要一个模块只调用一次的初始化函数。此函数是一个承诺,由执行函数调用。如果执行两次,第二次必须等待初始化,然后继续执行。
我写了这段代码,但是第二次调用 execute 总是在等待,而且永远不会 return。我错过了什么?
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
constructor 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);
});
});
}
resolved/rejected 承诺将保持其状态(已解决或拒绝状态),因此您可以将它用于 运行 初始化代码一次。为此,init()
函数应该 return 总是相同的承诺 而不是每次都创建它。
为此,我们在init()
方法之外创建一个延迟对象(initializationDeferred
),并使用initializationDeferred
到return相同的promise 每次调用 init()
方法。我们还需要检查 init()
之前是否已经完成,我们使用共享变量 initializationStarted
跳过 setTimeout
如果已经在之前的调用中完成。
现在,在 execute
中,您可以确定 then()
的 onFulfilled 回调仅在初始化 init()
方法时被调用。
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>
我需要一个模块只调用一次的初始化函数。此函数是一个承诺,由执行函数调用。如果执行两次,第二次必须等待初始化,然后继续执行。
我写了这段代码,但是第二次调用 execute 总是在等待,而且永远不会 return。我错过了什么?
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
constructor 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);
});
});
}
resolved/rejected 承诺将保持其状态(已解决或拒绝状态),因此您可以将它用于 运行 初始化代码一次。为此,init()
函数应该 return 总是相同的承诺 而不是每次都创建它。
为此,我们在init()
方法之外创建一个延迟对象(initializationDeferred
),并使用initializationDeferred
到return相同的promise 每次调用 init()
方法。我们还需要检查 init()
之前是否已经完成,我们使用共享变量 initializationStarted
跳过 setTimeout
如果已经在之前的调用中完成。
现在,在 execute
中,您可以确定 then()
的 onFulfilled 回调仅在初始化 init()
方法时被调用。
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>