UNPKG

react-native-background-geolocation

Version:

The most sophisticated cross-platform background location-tracking & geofencing module with battery-conscious motion-detection intelligence

854 lines (793 loc) 28.1 kB
'use strict' import { Platform, AppRegistry } from "react-native" import * as Events from './Events'; import NativeModule from './NativeModule'; import DeviceSettings from './DeviceSettings'; import Logger from './Logger'; import TransistorAuthorizationToken from './TransistorAuthorizationToken'; let _deviceSettingsInstance = null; const TAG = "BackgroundGeolocation"; const LOG_LEVEL_OFF = 0; const LOG_LEVEL_ERROR = 1; const LOG_LEVEL_WARNING = 2; const LOG_LEVEL_INFO = 3; const LOG_LEVEL_DEBUG = 4; const LOG_LEVEL_VERBOSE = 5; // This is a test. const DESIRED_ACCURACY_NAVIGATION = -2; const DESIRED_ACCURACY_HIGH = -1; const DESIRED_ACCURACY_MEDIUM = 10; const DESIRED_ACCURACY_LOW = 100; const DESIRED_ACCURACY_VERY_LOW = 1000; const DESIRED_ACCURACY_LOWEST = 3000; const AUTHORIZATION_STATUS_NOT_DETERMINED = 0; const AUTHORIZATION_STATUS_RESTRICTED = 1; const AUTHORIZATION_STATUS_DENIED = 2; const AUTHORIZATION_STATUS_ALWAYS = 3; const AUTHORIZATION_STATUS_WHEN_IN_USE = 4; const NOTIFICATION_PRIORITY_DEFAULT = 0; const NOTIFICATION_PRIORITY_HIGH = 1; const NOTIFICATION_PRIORITY_LOW =-1; const NOTIFICATION_PRIORITY_MAX = 2; const NOTIFICATION_PRIORITY_MIN =-2; const ACTIVITY_TYPE_OTHER = 1; const ACTIVITY_TYPE_AUTOMOTIVE_NAVIGATION = 2; const ACTIVITY_TYPE_FITNESS = 3; const ACTIVITY_TYPE_OTHER_NAVIGATION = 4; const ACTIVITY_TYPE_AIRBORNE = 5; const LOCATION_AUTHORIZATION_ALWAYS = "Always"; const LOCATION_AUTHORIZATION_WHEN_IN_USE = "WhenInUse"; const LOCATION_AUTHORIZATION_ANY = "Any"; const PERSIST_MODE_ALL = 2; const PERSIST_MODE_LOCATION = 1; const PERSIST_MODE_GEOFENCE = -1; const PERSIST_MODE_NONE = 0; const ACCURACY_AUTHORIZATION_FULL = 0; const ACCURACY_AUTHORIZATION_REDUCED = 1; const emptyFn = function() {} export default class BackgroundGeolocation { static get EVENT_BOOT() { return Events.BOOT; } static get EVENT_TERMINATE() { return Events.TERMINATE; } static get EVENT_LOCATION() { return Events.LOCATION; } static get EVENT_MOTIONCHANGE() { return Events.MOTIONCHANGE; } static get EVENT_HTTP() { return Events.HTTP; } static get EVENT_HEARTBEAT() { return Events.HEARTBEAT; } static get EVENT_PROVIDERCHANGE() { return Events.PROVIDERCHANGE; } static get EVENT_ACTIVITYCHANGE() { return Events.ACTIVITYCHANGE; } static get EVENT_GEOFENCE() { return Events.GEOFENCE; } static get EVENT_GEOFENCESCHANGE() { return Events.GEOFENCESCHANGE; } static get EVENT_ENABLEDCHANGE() { return Events.ENABLEDCHANGE; } static get EVENT_CONNECTIVITYCHANGE() { return Events.CONNECTIVITYCHANGE; } static get EVENT_SCHEDULE() { return Events.SCHEDULE; } static get EVENT_POWERSAVECHANGE() { return Events.POWERSAVECHANGE; } static get EVENT_NOTIFICATIONACTION() { return Events.NOTIFICATIONACTION; } static get EVENT_AUTHORIZATION() { return Events.AUTHORIZATION; } static get LOG_LEVEL_OFF() { return LOG_LEVEL_OFF; } static get LOG_LEVEL_ERROR() { return LOG_LEVEL_ERROR; } static get LOG_LEVEL_WARNING() { return LOG_LEVEL_WARNING; } static get LOG_LEVEL_INFO() { return LOG_LEVEL_INFO; } static get LOG_LEVEL_DEBUG() { return LOG_LEVEL_DEBUG; } static get LOG_LEVEL_VERBOSE() { return LOG_LEVEL_VERBOSE; } static get ACTIVITY_TYPE_OTHER() { return ACTIVITY_TYPE_OTHER;} static get ACTIVITY_TYPE_AUTOMOTIVE_NAVIGATION() { return ACTIVITY_TYPE_AUTOMOTIVE_NAVIGATION;} static get ACTIVITY_TYPE_FITNESS() { return ACTIVITY_TYPE_FITNESS;} static get ACTIVITY_TYPE_OTHER_NAVIGATION() { return ACTIVITY_TYPE_OTHER_NAVIGATION;} static get ACTIVITY_TYPE_AIRBORNE() { return ACTIVITY_TYPE_AIRBORNE; } static get DESIRED_ACCURACY_NAVIGATION() { return DESIRED_ACCURACY_NAVIGATION; } static get DESIRED_ACCURACY_HIGH() { return DESIRED_ACCURACY_HIGH; } static get DESIRED_ACCURACY_MEDIUM() { return DESIRED_ACCURACY_MEDIUM; } static get DESIRED_ACCURACY_LOW() { return DESIRED_ACCURACY_LOW; } static get DESIRED_ACCURACY_VERY_LOW() { return DESIRED_ACCURACY_VERY_LOW; } static get DESIRED_ACCURACY_LOWEST() { return DESIRED_ACCURACY_LOWEST; } static get AUTHORIZATION_STATUS_NOT_DETERMINED() { return AUTHORIZATION_STATUS_NOT_DETERMINED; } static get AUTHORIZATION_STATUS_RESTRICTED() { return AUTHORIZATION_STATUS_RESTRICTED; } static get AUTHORIZATION_STATUS_DENIED() { return AUTHORIZATION_STATUS_DENIED; } static get AUTHORIZATION_STATUS_ALWAYS() { return AUTHORIZATION_STATUS_ALWAYS; } static get AUTHORIZATION_STATUS_WHEN_IN_USE() { return AUTHORIZATION_STATUS_WHEN_IN_USE; } static get NOTIFICATION_PRIORITY_DEFAULT() { return NOTIFICATION_PRIORITY_DEFAULT; } static get NOTIFICATION_PRIORITY_HIGH() { return NOTIFICATION_PRIORITY_HIGH; } static get NOTIFICATION_PRIORITY_LOW() { return NOTIFICATION_PRIORITY_LOW; } static get NOTIFICATION_PRIORITY_MAX() { return NOTIFICATION_PRIORITY_MAX; } static get NOTIFICATION_PRIORITY_MIN() { return NOTIFICATION_PRIORITY_MIN; } static get LOCATION_AUTHORIZATION_ALWAYS() { return LOCATION_AUTHORIZATION_ALWAYS} static get LOCATION_AUTHORIZATION_WHEN_IN_USE() { return LOCATION_AUTHORIZATION_WHEN_IN_USE} static get LOCATION_AUTHORIZATION_ANY() { return LOCATION_AUTHORIZATION_ANY} static get PERSIST_MODE_ALL() { return PERSIST_MODE_ALL; } static get PERSIST_MODE_LOCATION() { return PERSIST_MODE_LOCATION; } static get PERSIST_MODE_GEOFENCE() { return PERSIST_MODE_GEOFENCE; } static get PERSIST_MODE_NONE() { return PERSIST_MODE_NONE; } static get ACCURACY_AUTHORIZATION_FULL() { return ACCURACY_AUTHORIZATION_FULL; } static get ACCURACY_AUTHORIZATION_REDUCED() { return ACCURACY_AUTHORIZATION_REDUCED; } static get deviceSettings() { if (_deviceSettingsInstance === null) { _deviceSettingsInstance = new DeviceSettings(); } return _deviceSettingsInstance; } /** * Core Plugin Control Methods */ static ready(config, success, failure) { if (arguments.length <= 1) { return NativeModule.ready(config||{}); } else { NativeModule.ready(config).then(success).catch(failure); } } /** * Reset plugin confg to default */ static reset(config, success, failure) { if ((typeof(config) == 'function') || (typeof(success) === 'function')) { if (typeof(config) === 'function') { success = config; } NativeModule.reset(config).then(success).catch(failure); } else { return NativeModule.reset(config); } } /** * Perform initial configuration of plugin. Reset config to default before applying supplied configuration */ static configure(config, success, failure) { if (arguments.length == 1) { return NativeModule.configure(config); } else { NativeModule.configure(config).then(success).catch(failure); } } static requestPermission(success, failure) { if (!arguments.length) { return NativeModule.requestPermission(); } else { NativeModule.requestPermission().then(success).catch(failure); } } static requestTemporaryFullAccuracy(purpose) { return NativeModule.requestTemporaryFullAccuracy(purpose); } static getProviderState(success, failure) { if (!arguments.length) { return NativeModule.getProviderState(); } else { NativeModule.getProviderState().then(success).catch(failure); } } /** * Listen to a plugin event */ static addListener(event, success, failure) { if (typeof(event) != 'string') { throw "BackgroundGeolocation#on must be provided a {String} event as 1st argument." } if (Events[event]) { throw "BackgroundGeolocation#on - Unknown event '" + event + "'" } if (typeof(success) != 'function') { throw "BackgroundGeolocation#on must be provided a callback as 2nd argument. If you're attempting to use the Promise API to listen to an event, it won't work, since a Promise can only evaluate once, while the callback function must be executed for each event." } return NativeModule.addListener.apply(NativeModule, arguments); } // @alias #removeListener static on(event, success, failure) { return this.addListener.apply(this, arguments); } static onLocation(success, failure) { return this.addListener(Events.LOCATION, success, failure); } static onMotionChange(callback) { return this.addListener(Events.MOTIONCHANGE, callback); } static onHttp(callback) { return this.addListener(Events.HTTP, callback); } static onHeartbeat(callback) { return this.addListener(Events.HEARTBEAT, callback); } static onProviderChange(callback) { return this.addListener(Events.PROVIDERCHANGE, callback); } static onActivityChange(callback) { return this.addListener(Events.ACTIVITYCHANGE, callback); } static onGeofence(callback) { return this.addListener(Events.GEOFENCE, callback); } static onGeofencesChange(callback) { return this.addListener(Events.GEOFENCESCHANGE, callback); } static onSchedule(callback) { return this.addListener(Events.SCHEDULE, callback); } static onEnabledChange(callback) { return this.addListener(Events.ENABLEDCHANGE, callback); } static onConnectivityChange(callback) { return this.addListener(Events.CONNECTIVITYCHANGE, callback); } static onPowerSaveChange(callback) { return this.addListener(Events.POWERSAVECHANGE, callback); } static onNotificationAction(callback) { return this.addListener(Events.NOTIFICATIONACTION, callback); } static onAuthorization(callback) { return this.addListener(Events.AUTHORIZATION, callback); } /** * Remove a single plugin event-listener, supplying a reference to the handler initially supplied to #un */ static removeListener(event, handler, success, failure) { if (typeof(event) != 'string') { throw "BackgroundGeolocation#un must be provided a {String} event as 1st argument" } if (!Events[event.toUpperCase()]) { throw "BackgroundGeolocation#un - Unknown event '" + event + "'" } NativeModule.removeListener.apply(NativeModule, arguments); } // @alias #removeListener static un(event, handler, success, failiure) { this.removeListener.apply(this, arguments); } /** * Remove all event listeners */ static removeListeners(success, failure) { if (!arguments.length) { return NativeModule.removeListeners(); } else { NativeModule.removeListeners().then(success).catch(failure); } } // @alias -> #removeListeners static removeAllListeners(success, failure) { this.removeListeners.apply(this, arguments); } /** * Fetch current plugin configuration */ static getState(success, failure) { if (!arguments.length) { return NativeModule.getState(); } else { NativeModule.getState().then(success).catch(failure); } } /** * Start the plugin */ static start(success, failure) { if (!arguments.length) { return NativeModule.start(); } else { NativeModule.start().then(success).catch(failure); } } /** * Stop the plugin */ static stop(success, failure) { if (!arguments.length) { return NativeModule.stop(); } else { NativeModule.stop().then(success).catch(failure); } } /** * Start the scheduler */ static startSchedule(success, failure) { if (!arguments.length) { return NativeModule.startSchedule(); } else { NativeModule.startSchedule().then(success).catch(failure); } } /** * Stop the scheduler */ static stopSchedule(success, failure) { if (!arguments.length) { return NativeModule.stopSchedule(); } else { NativeModule.stopSchedule().then(success).catch(failure); } } /** * Initiate geofences-only mode */ static startGeofences(success, failure) { if (!arguments.length) { return NativeModule.startGeofences(); } else { NativeModule.startGeofences().then(success).catch(failure); } } /** * Start an iOS background-task, provding 180s of background running time */ static startBackgroundTask(success, failure) { if (!arguments.length) { return NativeModule.startBackgroundTask(); } else { if (typeof(success) !== 'function') { throw TAG + "#startBackgroundTask must be provided with a callback to recieve the taskId"; } NativeModule.startBackgroundTask().then(success).catch(failure); } } /** * Signal to iOS that your background-task from #startBackgroundTask is complete * TODO Rename native method #finish -> #stopBackgroundTask. */ static stopBackgroundTask(taskId, success, failure) { // No taskId? Ignore it. if (arguments.length == 1) { return NativeModule.stopBackgroundTask(taskId); } else { NativeModule.stopBackgroundTask(taskId).then(success).catch(failure); } } /** * @deprecated Use #stopBackgroundTask */ static finish(taskId, success, failure) { this.stopBackgroundTask.apply(this, arguments); } /** * Register HeadlessTask * Have to wrap execution to finish our own headless-task because there's an unknown issue with TurboModules in new arch * where RN's HeadlessJsTaskSupport is null. That module can automatically finish RN headless-tasks. */ static registerHeadlessTask(taskProvider) { AppRegistry.registerHeadlessTask(TAG, () => { // return to RN's AppRegistry a Function that returns a Promise. return (event) => { return new Promise((resolve, reject) => { const taskId = event._transistorHeadlessTaskId; delete(event._transistorHeadlessTaskId); taskProvider(event).then(() => { BackgroundGeolocation.finishHeadlessTask(taskId); resolve(); }).catch(reason => { BackgroundGeolocation.finishHeadlessTask(taskId); reject(reason); }); }); } }); } /** * @private * Signal completion of a react-native headless-task. This helps RN free-up resources allocated to the headless-task execution. */ static finishHeadlessTask(taskId, success, failure) { if (arguments.length == 1) { return NativeModule.finishHeadlessTask(taskId); } else { NativeModule.finishHeadlessTask(taskId).then(success).catch(failure); } } /** * Toggle motion-state between stationary <-> moving */ static changePace(isMoving, success, failure) { if (arguments.length == 1) { return NativeModule.changePace(isMoving); } else { NativeModule.changePace(isMoving).then(success).catch(failure); } } /** * Provide new configuration to the plugin. This configuration will be *merged* to current configuration */ static setConfig(config, success, failure) { if (arguments.length == 1) { return NativeModule.setConfig(config); } else { NativeModule.setConfig(config).then(success).catch(failure); } } /** * HTTP & Persistence * */ static getLocations(success, failure) { if (!arguments.length) { return NativeModule.getLocations(); } else { NativeModule.getLocations().then(success).catch(failure); } } /** * Fetch the current count of location records in database */ static getCount(success, failure) { if (!arguments.length) { return NativeModule.getCount(); } else { NativeModule.getCount().then(success).catch(failure); } } /** * Destroy all records in locations database */ static destroyLocations(success, failure) { if (!arguments.length) { return NativeModule.destroyLocations(); } else { NativeModule.destroyLocations().then(success).catch(failure); } } /** * Destroy a single location by uuid */ static destroyLocation(uuid) { return NativeModule.destroyLocation(uuid); } /** * Destroy a single record by uuid */ // @deprecated static clearDatabase(success, failure) { return this.destroyLocations.apply(this, arguments); } /** * Insert a single record into locations database */ static insertLocation(location, success, failure) { if (arguments.length == 1) { return NativeModule.insertLocation(location); } else { NativeModule.insertLocation(location).then(success).catch(failure); } } /** * Manually initiate an HTTP sync operation */ static sync(success, failure) { if (!arguments.length) { return NativeModule.sync(); } else { NativeModule.sync().then(success).catch(failure); } } /** * Fetch the current value of odometer */ static getOdometer(success, failure) { if (!arguments.length) { return NativeModule.getOdometer(); } else { NativeModule.getOdometer().then(success).catch(failure); } } /** * Set the value of the odometer */ static setOdometer(value, success, failure) { if (arguments.length == 1) { return NativeModule.setOdometer(value); } else { NativeModule.setOdometer(value).then(success).catch(failure); } } /** * Reset the value of odometer to 0 */ static resetOdometer(success, failure) { if (!arguments.length) { return NativeModule.setOdometer(0); } else { NativeModule.setOdometer(0).then(success).catch(failure); } } /** * Geofencing Methods */ /** * Add a single geofence */ static addGeofence(config, success, failure) { if (arguments.length == 1) { return NativeModule.addGeofence(config); } else { NativeModule.addGeofence(config).then(success).catch(failure); } } /** * Remove a single geofence by identifier */ static removeGeofence(identifier, success, failure) { if (arguments.length == 1) { return NativeModule.removeGeofence(identifier); } else { NativeModule.removeGeofence(identifier).then(success).catch(failure); } } /** * Add a list of geofences */ static addGeofences(geofences, success, failure) { if (arguments.length == 1) { return NativeModule.addGeofences(geofences); } else { NativeModule.addGeofences(geofences).then(success).catch(failure); } } /** * Remove geofences. You may either supply an array of identifiers or nothing to destroy all geofences. * 1. removeGeofences() <-- Promise * 2. removeGeofences(['foo']) <-- Promise * * 3. removeGeofences(success, [failure]) * 4. removeGeofences(['foo'], success, [failure]) */ static removeGeofences(success, failure) { if (!arguments.length) { return NativeModule.removeGeofences(); } else { NativeModule.removeGeofences().then(success).catch(failure); } } /** * Fetch all geofences from database */ static getGeofences(success, failure) { if (!arguments.length) { return NativeModule.getGeofences(); } else { NativeModule.getGeofences().then(success).catch(failure); } } /** * Fetch a single geofence */ static getGeofence(identifier, success, failure) { if (arguments.length == 1) { return NativeModule.getGeofence(identifier); } else { NativeModule.getGeofence(identifier).then(success).catch(failure); } } /** * Return true if geofence was added */ static geofenceExists(identifier, success, failure) { if (arguments.length == 1) { return NativeModule.geofenceExists(identifier); } else { NativeModule.geofenceExists(identifier).then(success).catch(failure); } } /** * Fetch the current position from location-services */ static getCurrentPosition(options, success, failure) { if (typeof(options) === 'function') { throw "#getCurrentPosition requires options {} as first argument"; } if (typeof(success) === 'function') { NativeModule.getCurrentPosition(options).then(success).catch(failure); } else { return NativeModule.getCurrentPosition.apply(NativeModule, arguments); } } /** * Begin watching a stream of locations */ static watchPosition(success, failure, options) { if (typeof(success) === 'undefined') { throw TAG + '#watchPosition cannot use Promises since a Promise can only evaluate once while the supplied callback must be executed for each location'; } failure = failure || emptyFn; options = options || {}; NativeModule.watchPosition(success, failure, options); } /** * Stop watching location */ static stopWatchPosition(success, failure) { if (!arguments.length) { return NativeModule.stopWatchPosition(); } else { NativeModule.stopWatchPosition().then(success).catch(failure); } } /** * Set the logLevel. This is just a helper method for setConfig({logLevel: level}) */ static setLogLevel(value, success, failure) { if (arguments.length == 1) { return NativeModule.setLogLevel(value); } else { NativeModule.setLogLevel(value).then(success).catch(failure); } } /** * Fetch the entire contents of log database returned as a String */ static getLog(success, failure) { console.warn('[' + TAG + ' getLog] Deprecated. Use BackgroundGeolocation.logger.getLog'); if (!arguments.length) { return Logger.getLog(); } else { Logger.getLog().then(success).catch(failure); } } /** * Destroy all contents of log database */ static destroyLog(success, failure) { console.warn('[' + TAG + ' destroyLog] Deprecated. Use BackgroundGeolocation.logger.destroyLog'); if (!arguments.length) { return Logger.destroyLog(); } else { Logger.destroyLog().then(success).catch(failure); } } /** * Open deafult email client on device to email the contents of log database attached as a compressed file attachement */ static emailLog(email, success, failure) { console.warn('[' + TAG + ' emailLog] Deprecated. Use BackgroundGeolocation.logger.emailLog'); if (typeof(email) != 'string') { throw TAG + "#emailLog requires an email address as 1st argument"} if (arguments.length == 1) { return Logger.emailLog(email); } else { Logger.emailLog(email).then(success).catch(failure); } } /** * Has device OS initiated power-saving mode? */ static isPowerSaveMode(success, failure) { if (!arguments.length) { return NativeModule.isPowerSaveMode(); } else { NativeModule.isPowerSaveMode().then(success).catch(failure); } } /** * Fetch the state of this device's available motion-sensors */ static getSensors(success, failure) { if (!arguments.length) { return NativeModule.getSensors(); } else { NativeModule.getSensors().then(success).catch(failure); } } /** * Play a system sound via the plugin's Sound API */ static playSound(soundId, success, failure) { if (arguments.length == 1) { return NativeModule.playSound(soundId); } else { NativeModule.playSound(soundId).then(success).catch(failure); } } static findOrCreateTransistorAuthorizationToken(orgname, username, url) { return TransistorAuthorizationToken.findOrCreate(orgname, username, url); } static destroyTransistorAuthorizationToken(url) { return TransistorAuthorizationToken.destroy(url); } /** * Insert a log message into the plugin's log database */ static get logger() { return Logger; } static getDeviceInfo() { return NativeModule.getDeviceInfo(); } static async transistorTrackerParams() { let deviceInfo = await NativeModule.getDeviceInfo(); deviceInfo.uuid = deviceInfo.model; return { device: deviceInfo }; } /** * Iterate and execute API methods to test validity of method signature for both Standard and Promise API */ static test(delay) { test(this, delay); } } /** * Iterate and execute API methods to test validity of method signature for both Standard and Promise API */ var test = function(bgGeo, delay) { delay = delay || 250; var methods = [ ['reset', {debug: true, logLevel: 5}], ['setConfig', {distanceFilter: 50}], ['setLogLevel', 5], ['getLog', null], ['emailLog', 'foo@bar.com'], ['on', 'location'], ['ready', {}], ['configure', {debug: true, logLevel: 5, schedule: ['1-7 00:00-23:59']}], ['getState', null], ['startSchedule', null], ['stopSchedule', null], ['startGeofences', null], ['stop', null], ['start', null], ['startBackgroundTask', null], ['finish', 0], ['changePace', true], ['getLocations', null], ['insertLocation', {}], ['sync', null], ['getOdometer', null], ['setOdometer', 0], ['resetOdometer'], ['addGeofence', {identifier: 'test-geofence-1', radius: 100, latitude: 0, longitude:0, notifyOnEntry:true}], ['addGeofences', [{identifier: 'test-geofence-2', radius: 100, latitude: 0, longitude:0, notifyOnEntry:true}, {identifier: 'test-geofence-3', radius: 100, latitude: 0, longitude:0, notifyOnEntry:true}]], ['getGeofences', null], ['removeGeofence', 'test-geofence-1'], ['removeGeofences', null], ['getCurrentPosition', {}], ['watchPosition', {}], ['stopWatchPosition', null], ['isPowerSaveMode', null], ['getSensors', null], ['playSound', 1509], ['destroyLocations', null], ['clearDatabase', null], ['destroyLog', null], ['removeListeners', null] ]; var createCallback = function(type, method, params) { return function(result) { console.log('- ' + method + '(' + params + ') - ' + type + ': ', result); } } var executeMethod = function(record) { console.log('* Execute method: ', record) var method = '' + record[0]; var params = record[1]; var success = createCallback('success', method, params); var failure = createCallback('failure', method, params); // Execute Standard API try { console.log('- Standard API: ' + method); if (params == null) { bgGeo[method](success, failure); } else { // Adjust params for different signatures. switch (method) { case 'watchPosition': case 'getCurrentPosition': bgGeo[method](success, failure, params); break; default: bgGeo[method](params, success, failure); break; } } } catch (e) { console.warn(e); } // Execute Promise API setTimeout(function() { console.log('- Promise API: ' + method); try { if (params == null) { bgGeo[method]().then(success).catch(failure); } else { bgGeo[method](params).then(success).catch(failure); } } catch (e) { console.warn(e); } }, 10); } // Begin fetching methods. var intervalId = setInterval(function() { var record = methods.shift(); if (!record || !methods.length) { clearInterval(intervalId); console.log('*** TEST COMPLETE ***'); return; } executeMethod(record); }, delay); }