Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 28.04.2018, 14:57
Аспирант
Отправить личное сообщение для stweet Посмотреть профиль Найти все сообщения от stweet
 
Регистрация: 21.12.2011
Сообщений: 41

Синхронная запись в БД
День добрый форумчане! Устал бороться в одиночку с «асинхронностью» сии детища NodeJS. Прибегаю к помощи гуру Promises & Multyrequest.

Ситуация такая:
Допустим, у нас в базе (юзаю Pg + Sequalize) есть табличка с данными такого вида:

ID   TYPE    COUNTER
 1   «one»       1
 2   «two»       1


В модели есть методы decCounterByType(type); & incCounterByType(type); и вроде бы все ни чего пока не попробуешь использовать эти методы в цикле. Цикл же имитирует многочисленное обращение к базе, пример:

for(let i  = 0; i < 1000; i ++) {
	Model.incCounterByType(«one»)
		.then(res => console.log(`${i}, ${type}, ${res.counter}`))
		.catch(console.error);
}


Понимаем да, что вывод будет хаотичен и не каждое обращение получит правильный ответ, т. е. лог будет выглядеть примерно так:

0, «one», 1
3, «one», 2
1, «one», 4
2, «one», 3


Где то на просторах нашел решение, и да, оно работает, блокирует обращение:

let last = Promise.resolve({})
for(let i  = 0; i < 1000; i ++) {
	last  = last .then(() => Model.incCounterByType(«one»))
		.then(res => console.log(`${i}, ${type}, ${res.counter}`))
		.catch(console.error);
}


в этом случае у нас вывод будет уже:

0, «one», 1
1, «one», 2
2, «one», 3
3, «one», 4


и вроде бы эврика, решение есть! Но, под правильным углом со знаниями работы алгоритма Promise, мы понимаем, что если один из Promise не выполнит «resolve», или выполнит «reject» or «throw» все остальные обращения ждет фиаско. Пока остановился на таком варианте но уверен, за такой костыль будут бить ногами:

let last = Promise.resolve({})
for(let i  = 0; i < 1000; i ++) {
	last  = last .then(() => Model.incCounterByType(«one»))
		.then(res => console.log(`${i}, ${type}, ${res.counter}`))
		.catch(Promise.resolve));
}


Цель, добиться корректного обращения к БД и синхронный вывод результатов. А как вы блокируете обращения к БД?

Спасибо за участие в обсуждении!
Ответить с цитированием
  #2 (permalink)  
Старый 28.04.2018, 15:03
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 3,791

Что вы пытаетесь вообще сделать?
Почему не увеличить сразу все значения 1 запросом?
Ответить с цитированием
  #3 (permalink)  
Старый 28.04.2018, 15:11
Аспирант
Отправить личное сообщение для stweet Посмотреть профиль Найти все сообщения от stweet
 
Регистрация: 21.12.2011
Сообщений: 41

Сообщение от Nexus Посмотреть сообщение
Что вы пытаетесь вообще сделать?
Почему не увеличить сразу все значения 1 запросом?
Как вы себе это представляете? Зашло на сайт 100500 человек, сделали запросы а я их должен копить, и когда надумаю(видимо произвольно) сохраню, так?
Ответить с цитированием
  #4 (permalink)  
Старый 28.04.2018, 15:19
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 6,587

Если каждый юзер посылает запрос при заходе - каждый юзер получает свой ответ. И на момент ответа - этот ответ верен. В чём тогда проблема?
Чисто чтоб "порядок был" и цифры красивенькие?
__________________
29375, 35
Ответить с цитированием
  #5 (permalink)  
Старый 28.04.2018, 15:21
Аватар для EmperioAf
Профессор
Отправить личное сообщение для EmperioAf Посмотреть профиль Найти все сообщения от EmperioAf
 
Регистрация: 15.01.2015
Сообщений: 622

Async/await в помощь
async function foo() { // вернет Promise<undefined>
    for (let i = 0; i < 1000; i++) {
        try {
            const res = await Model.incCounterByType(«one»)
            console.log(`${i}, ${type}, ${res.counter}`)
        } catch(err) {
            // обработка ошибки
        }
    }
}
Ответить с цитированием
  #6 (permalink)  
Старый 28.04.2018, 15:24
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 3,791

stweet, перечитал, прошу прощение.
Не обратил внимание, что у вас это просто имитация.

C postgresql не работал, она не блокирует строку во время её обновления?
Ответить с цитированием
  #7 (permalink)  
Старый 28.04.2018, 15:33
Аспирант
Отправить личное сообщение для stweet Посмотреть профиль Найти все сообщения от stweet
 
Регистрация: 21.12.2011
Сообщений: 41

Сообщение от Aetae Посмотреть сообщение
Если каждый юзер посылает запрос при заходе - каждый юзер получает свой ответ. И на момент ответа - этот ответ верен. В чём тогда проблема?
Чисто чтоб "порядок был" и цифры красивенькие?
Скорее, мне важно правильное(надежное) выполнение кода. Что бы не получилось так, пока один юзер пытается поднять счетчик второй пытается его понизить и т.д. А в итоге каждый получает не разбириху, у второго счетчик уже поднялся, а у первого ещё ответ не пришел. Или это приблуды консоли и на рабочем примере все будет в порядке? Мне важно, что бы счетчик надежно работал. Если повторить туже операцию но с созданием записей, вы получите и в базе хаотичный счетчик. т.е.:
record 1 = 1
record 2 = 10
record 3 = 9
record 4 = 11
и т.д.
Ответить с цитированием
  #8 (permalink)  
Старый 28.04.2018, 15:34
Аспирант
Отправить личное сообщение для stweet Посмотреть профиль Найти все сообщения от stweet
 
Регистрация: 21.12.2011
Сообщений: 41

Сообщение от EmperioAf Посмотреть сообщение
Async/await в помощь
async function foo() { // вернет Promise<undefined>
    for (let i = 0; i < 1000; i++) {
        try {
            const res = await Model.incCounterByType(«one»)
            console.log(`${i}, ${type}, ${res.counter}`)
        } catch(err) {
            // обработка ошибки
        }
    }
}
Вы выполните свой код и посмотрите на результат.
Ответить с цитированием
  #9 (permalink)  
Старый 28.04.2018, 15:39
Аспирант
Отправить личное сообщение для stweet Посмотреть профиль Найти все сообщения от stweet
 
Регистрация: 21.12.2011
Сообщений: 41

Сообщение от Nexus Посмотреть сообщение
stweet, перечитал, прошу прощение.
Не обратил внимание, что у вас это просто имитация.

C postgresql не работал, она не блокирует строку во время её обновления?
По идее любая база должна блокировать обращение до его завершения. По тому и не видел проблем пока не столкнулся с выводом и/или попыткой изменить записи. Если 100500 человек одновременно попытаются внести изменения в запись, ответ будет хаотичен.

Пример такой, есть счетчик, равен "3"
Если одновременно "два" юзера жмякнут на "поднять" оба получают "4". А в базе стоит "5" - !неудачный пример!
Если два юзера одновременно зарегистрируются, счетчик идти у них будет не по порядку. - Скорее я об этом.

Последний раз редактировалось stweet, 28.04.2018 в 15:41.
Ответить с цитированием
  #10 (permalink)  
Старый 28.04.2018, 15:39
Аватар для EmperioAf
Профессор
Отправить личное сообщение для EmperioAf Посмотреть профиль Найти все сообщения от EmperioAf
 
Регистрация: 15.01.2015
Сообщений: 622

let GLOBAL_ITER = 0;

function iter() {
    return new Promise((resolve) => {
        setTimeout(() => { 
            GLOBAL_ITER++;
            resolve(GLOBAL_ITER);
        }, 1e3);
    });
}

async function test() {
    for (let i = 0; i < 5; i++) {
        try {
            const curGlobalIter = await iter();
            console.log(curGlobalIter)
        } catch(err) {
        
        }
    }
}

test().then(() => console.log('done'));

как вы можете понять, я увижу постепенно появившиеся с delay 1с
1
2
3
4
5
done
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Запись видео с экрана prog77 Библиотеки/Тулкиты/Фреймворки 5 10.02.2020 18:31
getUserMedia() как отследить последующие изменения разрешений на запись? Amateur Элементы интерфейса 0 20.10.2015 22:30
Store - просто удалить запись Infarch ExtJS 1 12.08.2014 17:46
VK - разместить запись на стену lol4eg Общие вопросы Javascript 8 23.02.2013 14:52
Как сделать чтобы пользователь только мог 2 раза прослушать запись? KOTDG AJAX и COMET 0 11.02.2012 22:37