Асинхронная вставка SQL в цикле

У меня проблемы с вставкой строк в базу данных SQL. Я хочу превратить массив объектов в таблицу SQL в JavaScript.

Следующий код добавляет только первый объект массива. Я перепробовал все, что смог найти в stackru и в других местах и ​​не могу заставить его работать.

Любая помощь будет оценена. Благодарю.

        for (var i = 0; i < arr.length; i++) {
            db.save({key:i+"", value:arr[i]}, function(e){

            });
        }

ОБНОВЛЕНИЕ 1: я изменил это к примеру с mathec и немного сузил проблему.

Количество вставляемых строк зависит от размера вставляемого объекта. Так что это связано со временем, которое требуется для обработки каждого объекта.

Как мне обойти эту проблему? Благодарю.

Обновление 2:

Я взял предложение Роберта Янга ниже и включил самодостаточный пример.

В приведенном ниже примере вставляются только первые 5 элементов. Если я удаляю часть текста слова в тестовом ключе, чтобы он произносил слово "только один раз", вставляются 10 элементов. Так что теперь я уверен, что это связано со временем, которое требуется для обработки каждого объекта.

<html>
    <head>
        <script src="jquery.js"></script>
        <script src="lawnchair.js"></script>
        <script type='text/javascript'>


            var db = "";
            var arr = [];

            arr.push({name:"a1", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a2", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a3", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a4", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a5", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a6", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a7", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a8", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a9", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a10", test:"word word word word word word word word word word word word word word "});
            arr.push({name:"a11", test:"word word word word word word word word word word word word word word "});

            $(function() {
                db = new Lawnchair({table:'t50'}, function(e){
                    for ( i = 0; i < arr.length; i++) {
                        (function(i) {
                            add_row(i);
                        }(i));
                    }
                });
            });

            function add_row(i) {
                db.save({key:i+"", value:arr[i]}, function(e){

                });
            }

        </script>
    </head>
    <body>

    </body>
</html>

ОБНОВЛЕНИЕ 3: я использовал предложенный Робертом код и придумал следующее, которое работало с тремя небольшими элементами. Поэтому я изменил первый элемент, сделав его больше других, чтобы протестировать его. Первый элемент не был добавлен, а последние два были. Есть ли ограничения по времени для обработки массива?

<html>
    <head>
        <script src="jquery.js"></script>
        <script src="lawnchair.js"></script>
        <script type='text/javascript'>

            var arr = [];
            var db = "";

            $(function() {
                db = new Lawnchair({table:'t51'}, function(e){
                    arr=[{key:"k1", value:"v1. Because the contents of this element are larger than the others it will not be added for some reason. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. "}
                    ,{key:"k2", value:"v2"}
                    ,{key:"k3", value:"v3"}]

                    db.batch(arr, function () {
                        db.all(function (recs) { for (r in recs) {console.log(recs[r].key +"| "+ recs[r].value) } });
                    });
                });

            });

        </script>
    </head>
    <body>
    </body>
</html>

3 ответа

Решение

Во-первых, поскольку это постоянное хранилище, если вы будете запускать его снова и снова, вы можете каждый раз получать разные результаты, поскольку не инициализируете постоянное хранилище. Было бы неплохо добавить в db.nuke() чтобы убедиться, что вы начинаете с чистого листа, по крайней мере, пока вы не решите какие-либо ошибки.

Главное, что нужно знать об асинхронном хранении, это то, что возвращаемая функция не означает, что данные на самом деле сохранены. Так что если вы бежите

db = new Lawnchair(function(db){
    db.save({key:"value"})
    db.get("foo", function (rec) { console.log(rec.value) });
});

это может или не может работать, потому что когда вы вызываете db.get, значение может сохраняться или не сохраняться.

Чтобы это работало, мы должны быть уверены, что значение сохранено, прежде чем мы вызовем db.get. Способ сделать это - использовать обратные вызовы - если вы передадите два аргумента в db.save, он вызовет второй аргумент после сохранения значения. Так

db = new Lawnchair(function(db){
    db.save({key:"foo", value:"bar"}, function () {
        db.get("foo", function (rec) { console.log(rec.value) });
    });
});

работает отлично.

Это становится трудным, когда вы пытаетесь сохранить несколько значений, потому что вы хотите быть уверены, что все они сохранены. К счастью, есть функция для этого, batch:

db = new Lawnchair(function(db){
    arr=[{key:"k1", value:"v1"},{key:"k2", value:"v2"},{key:"k3", value:"v3"}];
    db.batch(arr, function () {
        db.all(function (recs) { for (r in recs) {console.log(recs[r].key) } });
    });
});

должен выводить

k1
k2
k3

Попробуйте и посмотрите, что получится.

Хитрая ошибка, которую я совершил сам несколько раз:-). Если внутри цикла вызывается функция обратного вызова, она будет вызываться асинхронно. Итак, ваш цикл будет продолжать выполняться до конца. Чтобы решить эту проблему, нужно сформировать замыкание вокруг текущего значения i, чтобы при выполнении функции обратного вызова оно связывалось с правым значением i. Что-то вроде этого:

function doSomething(i) {
  console.log(i)
}

var i, len;

for ( i = 0; i < 10; i++) {
  (function(i) {
    doSomething(i);
  }(i));
}

Функция внутри цикла будет выполнена немедленно, но значение i останется в области видимости.

Трудно сузить решение проблемы, потому что мы не знаем, как вы сохраняете данные в БД, может быть, это AJAX-запрос? Но я думаю, что проблема заключается во всей логике сохранения каждой строки массива асинхронно потому что код не ждет, пока одна строка будет сохранена, чтобы запустить другую, поэтому возникает какое-то условие гонки, и некоторые строки сохраняются в одном и том же "id" (поле автоинкремента), и это объясняет, почему сохраняются только некоторые строки,

Я предлагаю отправить весь массив на сервер, а затем вы сохраните каждую строку.

Конечно, вы могли бы сделать для каждой строки сначала блокировку идентификатора, а затем сохранить данные, но это плохая идея, потому что вам нужно туда и обратно к серверу и БД для каждой строки, удваивая количество запросов к серверу.

Надеюсь, поможет!

PD +1 к ответу @mathec за указание на циклическую переменную с проблемой обратного вызова!

Другие вопросы по тегам