我在Visual Studio中使用Cordova开发iOS应用程序并且它不断返回此错误:

There is no handler for the following exec call: SQLitePlugin.close({"path":"mobileapps.db"})

我相信在尝试合并在线服务器和本地表时会发生这种情况 . 控制台显示:

OPEN database: mobileapps.db database already open: mobileapps.db new transaction is queued, waiting for open operation to finish

这是我的db.js文件的全部内容(我一直在修改示例todolist Cordova应用程序):

(function () {
"use strict";

var client, // Connection to the Azure Mobile App backend
    store,  // Sqlite store to use for offline data sync
    syncContext, // Offline data sync context
    tableName = 'couponCounts',
    couponTable; // Reference to a table endpoint on backend

// Set useOfflineSync to true to use tables from local store.
// Set useOfflineSync to false to use tables on the server.
var useOfflineSync = true;

// Add an event listener to call our initialization routine when the host is ready
document.addEventListener('deviceready', onDeviceReady); // false option was enabled before; relevant?

// Event Handler, called when the host is ready
function onDeviceReady() {
    console.log("onDeviceReady() called!");

    // Create a connection reference to our Azure Mobile Apps backend 
    client = new WindowsAzure.MobileServiceClient('https://jessica-wants.azurewebsites.net'); // ?ZUMO-API-VERSION=2.0.0

    if (useOfflineSync) {
        initializeStore().then(setup);
    } else {
        setup();
    }
}

/**
 * Set up and initialize the local store.
 */
function initializeStore() {
    console.log("initializeStore() running!");

    // Create the sqlite store
    store = new WindowsAzure.MobileServiceSqliteStore();

    // Define the table schema
    return store.defineTable({
        name: tableName,
        columnDefinitions: {
            id: 'string', // The coupon
            count: 'integer' // The number of that particular coupon remaining
        }
    }).then(function () {
        // Initialize the sync context
        syncContext = client.getSyncContext();

        // Define an overly simplified push handler that discards
        // local changes whenever there is an error or conflict.
        // Note that a real world push handler will have to take action according
        // to the nature of conflict.
        syncContext.pushHandler = {
            onConflict: function (pushError) {
                return pushError.cancelAndDiscard();
            },
            onError: function (pushError) {
                return pushError.cancelAndDiscard();
            }
        };

        return syncContext.initialize(store);
    }, function (error) {
        console.error(error);
    });
}

/**
 * Set up the tables, event handlers and load data from the server 
 */
function setup() {
    console.log("setup() running!");

    // Create a table reference
    if (useOfflineSync) {
        couponTable = client.getSyncTable(tableName);
    } else {
        couponTable = client.getTable(tableName);
    }

    // Cycles over local coupons and ensures that the database contains copies
    var coupons = $('.count'), i;
    for (i = 0; i < coupons.length; i++) {
        var coupon = {
            id: coupons[i].id,
            count: parseInt(coupons[i].innerText)
        };

        couponTable
            .insert(coupon) // Do something else? Sync w/ online/local? Which one is this?!?!?!
            .then(function () {
                console.log("Inserted coupon to table! Coupon: ");
                console.log(coupon);
            });
    }

    // Refresh the counts
    refreshDisplay();

    // Adds event handlers
    addEventHandlers();
}

function addEventHandlers() {
    // Wire up the UI Event Handler
    var coupons = document.querySelectorAll("#home button"), counts = $('.count'), i;
    for (i = 0; i < coupons.length; i++) {
        // Unbinding the click handler first prevents the function from being called twice [.unbind('click')]
        $(coupons[i]).click(function () {
            redeemCoupon(this.id);
            refreshDisplay();
        });

        $(counts[i]).on('change', function () {
            var coupon = this.id;
            var newCount = this.text();
            updateTable(coupon, newCount);
        });
    }
}

/**
 * Refresh the display with items from the table.
 * If offline sync is enabled, the local table will be synchronized
 * with the server table before displaying the counts.
 */
function refreshDisplay() {
    console.log("refreshDisplay() running!");

    if (useOfflineSync) {
        syncLocalTable().then(displayCounts);
    } else {
        displayCounts();
    }
}

/**
 * Synchronize local table with the table on the server.
 * We do this by pushing local changes to the server and then
 * pulling the latest changes from the server.
 */
function syncLocalTable() {
    console.log("syncLocalTable() running!");

    return syncContext
        .push()
        .then(function () {
            return syncContext.pull(new WindowsAzure.Query(tableName));
        });
}

/**
 * Displays the counts for the various coupons
 */
function displayCounts() {
    console.log("displayCounts() running!");

    // Execute a query for uncompleted items and process
    couponTable
        .where({ complete: false })     // Set up the query (?)
        .read()                         // Read the results
        .then(applyOnlineCounts, handleError);
}

/**
 * Create the DOM for a single coupon
 * @param {Object} coupon the coupon
 * @param {string} coupon.id the ID of the coupon
 * @param {integer} coupon.count the number of that coupon remaining
 * @returns {jQuery} jQuery DOM object
 */
var numInRow = 0;
function createCoupon(coupon) {
    // Because the old DOM is still loaded at this point, I can just pull the manually typed name.
    var couponName = $("button#" + coupon.id).text();
    var finalButton = $('<button id="' + coupon.id + '"><span class="overflow">' + couponName + '</span></button>');
    console.log(coupon);

    if (numInRow == 0) {
        // Creates a row
        numInRow++;
        return $('<div class="row">')
            .append($(finalButton));
    } else if (numInRow < 3) {
        // Adds to the row
        numInRow++;
        return finalButton;
    } else {
        // Finishes the row
        numInRow = 0;
        return $(finalButton)
            .append($('</div>'));
    }
}

// Applies the counts from the Azure table locally
function applyOnlineCounts(coupons) {
    console.log("applyOnlineCounts(coupons) running!");
    var couponList = $.map(coupons, createCoupon);

    console.log("Coupons (applyOnlineCounts):");
    console.log(couponList);

    // Cycle through each coupon received from Azure and update the local counts
    $('#coupon-display').empty().append(couponList); // .toggle(listItems.length > 0)

    // Adds event handlers
    addEventHandlers();
}

// Default error handler; just logs to console to hide problems from end user
function handleError(error) {
    console.log("handleError():");

    var text = error + (error.request ? ' - ' + error.request.status : '');
    console.error(text);
}

// Updates the online table after activating the coupon
function updateTable(coupon, newCount) {
    console.log("updateTable() running!");

    // coupon = ID of coupon redeemed
    // newCount = the number of the coupon left
    couponTable
        .update({ id: coupon, count: newCount }) // Async send the update to backend
        .then(function () {
            console.log("Updated table! New values: " + coupon + ", " + newCount);
        });
}
})();

如果你需要,我可以上传其他文件,但我已经在这个问题上苦苦挣扎数周了 . 任何帮助将不胜感激 .