MDL-79194 core_courseformat: optimize section reload
* When reloading a section, we also forced the reloading of course modules, resulting in doing the same work twice (once for the section reload and once for the course module reload) * Debounce the reloading process so prevent unwanted duplicate reloads
This commit is contained in:
committed by
Laurent David
parent
560c42964d
commit
41f098e7da
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -524,12 +524,12 @@ export default class Component extends BaseComponent {
|
||||
if (debouncedReload) {
|
||||
return debouncedReload;
|
||||
}
|
||||
const pendingReload = new Pending(pendingKey);
|
||||
const reload = () => {
|
||||
const pendingReload = new Pending(pendingKey);
|
||||
this.debouncedReloads.delete(pendingKey);
|
||||
const cmitem = this.getElement(this.selectors.CM, cmId);
|
||||
if (!cmitem) {
|
||||
return;
|
||||
return pendingReload.resolve();
|
||||
}
|
||||
const promise = Fragment.loadFragment(
|
||||
'core_courseformat',
|
||||
@@ -542,17 +542,45 @@ export default class Component extends BaseComponent {
|
||||
}
|
||||
);
|
||||
promise.then((html, js) => {
|
||||
// Other state change can reload the CM or the section before this one.
|
||||
if (!document.contains(cmitem)) {
|
||||
pendingReload.resolve();
|
||||
return false;
|
||||
}
|
||||
Templates.replaceNode(cmitem, html, js);
|
||||
this._indexContents();
|
||||
pendingReload.resolve();
|
||||
return;
|
||||
}).catch();
|
||||
return true;
|
||||
}).catch(() => {
|
||||
pendingReload.resolve();
|
||||
});
|
||||
return pendingReload;
|
||||
};
|
||||
debouncedReload = debounce(reload, 200);
|
||||
debouncedReload = debounce(
|
||||
reload,
|
||||
200,
|
||||
{
|
||||
cancel: true, pending: true
|
||||
}
|
||||
);
|
||||
this.debouncedReloads.set(pendingKey, debouncedReload);
|
||||
return debouncedReload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the active reload CM debounced function, if any.
|
||||
* @param {Number} cmId
|
||||
*/
|
||||
_cancelDebouncedReloadCm(cmId) {
|
||||
const pendingKey = `courseformat/content:reloadCm_${cmId}`;
|
||||
const debouncedReload = this.debouncedReloads.get(pendingKey);
|
||||
if (!debouncedReload) {
|
||||
return;
|
||||
}
|
||||
debouncedReload.cancel();
|
||||
this.debouncedReloads.delete(pendingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload a course section contents.
|
||||
*
|
||||
@@ -566,6 +594,10 @@ export default class Component extends BaseComponent {
|
||||
const pendingReload = new Pending(`courseformat/content:reloadSection_${element.id}`);
|
||||
const sectionitem = this.getElement(this.selectors.SECTION, element.id);
|
||||
if (sectionitem) {
|
||||
// Cancel any pending reload because the section will reload cms too.
|
||||
for (const cmId of element.cmlist) {
|
||||
this._cancelDebouncedReloadCm(cmId);
|
||||
}
|
||||
const promise = Fragment.loadFragment(
|
||||
'core_courseformat',
|
||||
'section',
|
||||
@@ -580,8 +612,9 @@ export default class Component extends BaseComponent {
|
||||
Templates.replaceNode(sectionitem, html, js);
|
||||
this._indexContents();
|
||||
pendingReload.resolve();
|
||||
return;
|
||||
}).catch();
|
||||
}).catch(() => {
|
||||
pendingReload.resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
define("core/utils",["exports","core/pending"],(function(_exports,_pending){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.throttle=_exports.debounce=void 0,_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};_exports.throttle=(func,wait)=>{let onCooldown=!1,runAgain=null;const run=function(){for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];runAgain=null!==runAgain,onCooldown||(func.apply(this,args),onCooldown=!0,setTimeout((()=>{const recurse=runAgain;onCooldown=!1,runAgain=null,recurse&&run(args)}),wait))};return run};const debounceMap=new Map;_exports.debounce=function(func,wait){let{pending:pending=!1}=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},timeout=null;const returnedFunction=function(){for(var _len2=arguments.length,args=new Array(_len2),_key2=0;_key2<_len2;_key2++)args[_key2]=arguments[_key2];pending&&!debounceMap.has(returnedFunction)&&debounceMap.set(returnedFunction,new _pending.default("core/utils:debounce")),clearTimeout(timeout),timeout=setTimeout((async()=>{const pendingPromise=debounceMap.get(returnedFunction);debounceMap.delete(returnedFunction),await func.apply(undefined,args),null==pendingPromise||pendingPromise.resolve()}),wait)};return returnedFunction}}));
|
||||
define("core/utils",["exports","core/pending"],(function(_exports,_pending){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.throttle=_exports.debounce=void 0,_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};_exports.throttle=(func,wait)=>{let onCooldown=!1,runAgain=null;const run=function(){for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];runAgain=null!==runAgain,onCooldown||(func.apply(this,args),onCooldown=!0,setTimeout((()=>{const recurse=runAgain;onCooldown=!1,runAgain=null,recurse&&run(args)}),wait))};return run};const debounceMap=new Map;_exports.debounce=function(func,wait){let{pending:pending=!1,cancel:cancel=!1}=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},timeout=null;const returnedFunction=function(){for(var _len2=arguments.length,args=new Array(_len2),_key2=0;_key2<_len2;_key2++)args[_key2]=arguments[_key2];pending&&!debounceMap.has(returnedFunction)&&debounceMap.set(returnedFunction,new _pending.default("core/utils:debounce")),clearTimeout(timeout),timeout=setTimeout((async()=>{const pendingPromise=debounceMap.get(returnedFunction);debounceMap.delete(returnedFunction),await func.apply(undefined,args),null==pendingPromise||pendingPromise.resolve()}),wait)};return cancel&&(returnedFunction.cancel=()=>{const pendingPromise=debounceMap.get(returnedFunction);null==pendingPromise||pendingPromise.resolve(),clearTimeout(timeout)}),returnedFunction}}));
|
||||
|
||||
//# sourceMappingURL=utils.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -87,6 +87,7 @@ const debounceMap = new Map();
|
||||
* @param {Number} wait The number of milliseconds to wait after the final attempt to execute
|
||||
* @param {Object} [options]
|
||||
* @param {boolean} [options.pending=false] Whether to wrap the debounced method in a pending promise
|
||||
* @param {boolean} [options.cancel=false] Whether to add a cancel method to the debounced function
|
||||
* @return {Function}
|
||||
*/
|
||||
export const debounce = (
|
||||
@@ -94,6 +95,7 @@ export const debounce = (
|
||||
wait,
|
||||
{
|
||||
pending = false,
|
||||
cancel = false,
|
||||
} = {},
|
||||
) => {
|
||||
let timeout = null;
|
||||
@@ -119,5 +121,13 @@ export const debounce = (
|
||||
}, wait);
|
||||
};
|
||||
|
||||
if (cancel) {
|
||||
returnedFunction.cancel = () => {
|
||||
const pendingPromise = debounceMap.get(returnedFunction);
|
||||
pendingPromise?.resolve();
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}
|
||||
|
||||
return returnedFunction;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.2.4 ===
|
||||
* Add a new parameter to the debounce (core/utils) function allow it to create its own own Pending promise.
|
||||
(via options.pending). This is a backport of patch MDL-78779.
|
||||
* Add a new parameter to the debounce (core/utils) function to allow for cancellation.
|
||||
|
||||
=== 4.2.3 ===
|
||||
* \moodle_page::set_title() has been updated to append the site name depending on the value of $CFG->sitenameintitle and whether
|
||||
the site's fullname/shortname has been set. So there's no need to manually add the site name whenever calling $PAGE->set_title().
|
||||
|
||||
Reference in New Issue
Block a user