cordova.define("cordova-plugin-googlemaps.commandQueueExecutor", function(require, exports, module) { /***************************************************************************** * Command queue mechanism * (Save the number of method executing at the same time) *****************************************************************************/ var cordova_exec = require('cordova/exec'), common = require('./Common'); var commandQueue = []; var _isWaitMethod = null; var _isExecuting = false; var _executingCnt = 0; var MAX_EXECUTE_CNT = 10; var _lastGetMapExecuted = 0; var _isResizeMapExecuting = false; // This flag becomes true when the page will be unloaded. var _stopRequested = false; function execCmd(success, error, pluginName, methodName, args, execOptions) { execOptions = execOptions || {}; // The JavaScript special keyword 'this' indicates `who call this function`. // This execCmd function is executed from overlay instances such as marker. // So `this` means `overlay` instance. var overlay = this; // If the overlay has been already removed from map, // do not execute any methods on it. if (overlay._isRemoved && !execOptions.remove) { console.error('[ignore]' + pluginName + '.' + methodName + ', because removed.'); return true; } // If the overlay is not ready in native side, // do not execute any methods except remove on it. // This code works for map class especially. if (!this._isReady && methodName !== 'remove') { console.error('[ignore]' + pluginName + '.' + methodName + ', because it\'s not ready.'); return true; } // Push the method into the commandQueue(FIFO) at once. commandQueue.push({ 'execOptions': execOptions, 'args': [ function() { //------------------------------- // success callback //------------------------------- if (methodName === 'resizeMap') { _isResizeMapExecuting = false; } // Even if the method was successful, // but the _stopRequested flag is true, // do not execute further code. if (!_stopRequested && success) { var results = Array.prototype.slice.call(arguments, 0); common.nextTick(function() { success.apply(overlay,results); }); } // Insert small delays only for `map.getMap()`, // because if you execute three or four `map.getMap()` at the same time, // Android OS itself crashes. // In order to prevent this error, insert small delays. var delay = 0; if (methodName === _isWaitMethod) { if (_isWaitMethod === 'getMap' && Date.now() - _lastGetMapExecuted < 1500) { delay = 1500; } _lastGetMapExecuted = Date.now(); _isWaitMethod = null; } setTimeout(function() { _executingCnt--; common.nextTick(_exec); }, delay); }, function() { //------------------------------- // error callback //------------------------------- if (methodName === 'resizeMap') { _isResizeMapExecuting = false; } if (!_stopRequested && error) { var results = Array.prototype.slice.call(arguments, 0); common.nextTick(function() { error.apply(overlay,results); }); } if (methodName === _isWaitMethod) { _isWaitMethod = null; } _executingCnt--; common.nextTick(_exec); }, pluginName, methodName, args] }); // In order to execute all methods in safe, // the maps plugin limits the number of execution in a moment to 10. // // Note that Cordova-Android drops has also another internal queue, // and the internal queue drops our statement if the app send too much. // // Also executing too much statements at the same time, // it would cause many errors in native side, such as out-of-memory. // // In order to prevent these troubles, the maps plugin limits the number of execution is 10. if (_isExecuting || _executingCnt >= MAX_EXECUTE_CNT || _isWaitMethod || commandQueue.length === 0) { return; } common.nextTick(_exec); } function _exec() { // You probably wonder why there is this code because it's already simular code at the end of the execCmd function. // // Because the commandQueue might change after the last code of the execCmd. // (And yes, it was occurred.) // In order to block surely, block the execution again. if (_isExecuting || _executingCnt >= MAX_EXECUTE_CNT || _isWaitMethod || commandQueue.length === 0) { return; } _isExecuting = true; // Execute some execution requests (up to 10) from the commandQueue. var methodName; while (commandQueue.length > 0 && _executingCnt < MAX_EXECUTE_CNT) { if (!_stopRequested) { _executingCnt++; } // Pick up the head one. var commandParams = commandQueue.shift(); methodName = commandParams.args[3]; // If the request is `map.refreshLayout()` and another `map.refreshLayout()` is executing, // skip it. // This prevents to execute multiple `map.refreshLayout()` at the same time. if (methodName === 'resizeMap') { if (_isResizeMapExecuting) { _executingCnt--; continue; } _isResizeMapExecuting = true; } // If the `_stopRequested` flag is true, // do not execute any statements except `remove()` or `clear()` methods. if (_stopRequested && (!commandParams.execOptions.remove || methodName !== 'clear')) { _executingCnt--; continue; } // Some methods have to block other execution requests, such as `map.clear()` if (commandParams.execOptions.sync) { _isWaitMethod = methodName; cordova_exec.apply(this, commandParams.args); break; } cordova_exec.apply(this, commandParams.args); } _isExecuting = false; } //---------------------------------------------------- // Stop all executions if the page will be closed. //---------------------------------------------------- function stopExecution() { // Request stop all tasks. _stopRequested = true; } window.addEventListener('unload', stopExecution); module.exports = execCmd; });