Последовательное выполнение операций в localForage строится вокруг промисов, поскольку каждая операция чтения или записи в хранилище является асинхронной. При работе с цепочками промисов ключевым становится управление порядком выполнения: каждая следующая операция должна опираться на результат предыдущей, не блокируя основной поток выполнения.
Каждый метод localForage — setItem,
getItem, removeItem, clear,
keys, length — возвращает Promise. Это
означает, что результат можно передавать дальше по цепочке через
then, формируя строго линейный поток выполнения.
Последовательность строится не через вложенные колбэки, а через
возврат значений из then, что позволяет выстраивать
читаемый и предсказуемый код.
localForage.setItem('user', { name: 'Alex' })
.then(() => localForage.getItem('user'))
.then(value => {
console.log(value);
});
Здесь каждая следующая операция стартует только после завершения предыдущей.
Цепочки промисов позволяют не только упорядочивать операции, но и
передавать данные между этапами. Возвращаемое значение из
then автоматически становится входным параметром следующего
обработчика.
localForage.setItem('counter', 1)
.then(() => localForage.getItem('counter'))
.then(value => {
const updated = value + 1;
return localForage.setItem('counter', updated);
})
.then(() => localForage.getItem('counter'))
.then(finalValue => {
console.log(finalValue);
});
Каждый шаг изменяет состояние и передает его дальше, формируя линейную цепь трансформаций данных.
Ключевое правило последовательных операций — всегда возвращать
Promise из then. Если этого не сделать, цепочка нарушается,
и следующий шаг выполняется без ожидания завершения асинхронной
операции.
localForage.setItem('a', 10)
.then(() => {
localForage.setItem('b', 20); // ошибка: нет return
})
.then(() => {
// выполняется раньше, чем завершится setItem('b')
console.log('Нарушение последовательности');
});
Правильная форма:
localForage.setItem('a', 10)
.then(() => {
return localForage.setItem('b', 20);
})
.then(() => {
console.log('Последовательность сохранена');
});
Возврат Promise гарантирует, что следующий then дождется
завершения операции.
При работе с локальным хранилищем часто требуется модифицировать существующее значение. Это приводит к типичному шаблону: получить данные → изменить → сохранить.
localForage.getItem('profile')
.then(profile => {
profile.lastLogin = Date.now();
profile.visits = (profile.visits || 0) + 1;
return localForage.setItem('profile', profile);
})
.then(updatedProfile => {
console.log(updatedProfile);
});
Такая структура исключает гонки состояний, поскольку каждая операция выполняется строго после предыдущей.
Иногда требуется гарантировать порядок сохранения нескольких ключей. Даже если операции независимы, их последовательность может быть важна для логики приложения.
localForage.setItem('step1', 'A')
.then(() => localForage.setItem('step2', 'B'))
.then(() => localForage.setItem('step3', 'C'))
.then(() => localForage.getItem('step3'))
.then(value => {
console.log(value);
});
Здесь каждая операция записи выполняется строго после завершения предыдущей, что исключает частично записанное состояние.
Цепочки промисов позволяют централизованно обрабатывать ошибки через
catch. Ошибка, возникшая на любом этапе, прерывает
дальнейшее выполнение и передается в обработчик.
localForage.setItem('data', { test: true })
.then(() => localForage.getItem('data'))
.then(data => {
throw new Error('Непредвиденная ошибка');
})
.then(() => localForage.setItem('next', 123))
.catch(err => {
console.error('Ошибка в цепочке:', err);
});
После возникновения ошибки последующие then не
выполняются, пока ошибка не будет обработана.
После обработки ошибки можно вернуть значение, и цепочка продолжит выполнение как обычно.
localForage.getItem('settings')
.then(settings => {
if (!settings) {
return localForage.setItem('settings', { theme: 'dark' });
}
return settings;
})
.then(result => {
return localForage.getItem('settings');
})
.then(finalSettings => {
console.log(finalSettings);
})
.catch(err => {
console.error(err);
});
Возврат значения из catch или промежуточной логики
позволяет восстановить поток выполнения.
localForage часто используется для миграций структуры данных. В таких сценариях цепочки промисов позволяют строго контролировать порядок операций: очистка → создание новых ключей → проверка.
localForage.clear()
.then(() => localForage.setItem('version', 2))
.then(() => localForage.setItem('config', { mode: 'safe' }))
.then(() => localForage.keys())
.then(keys => {
console.log('Созданные ключи:', keys);
});
Такая последовательность исключает частичное состояние базы, особенно при обновлении схемы хранения.
Цепочки промисов могут быть вынесены в функции, что позволяет переиспользовать последовательности операций.
function initializeStorage() {
return localForage.clear()
.then(() => localForage.setItem('initialized', true))
.then(() => localForage.setItem('timestamp', Date.now()));
}
initializeStorage()
.then(() => localForage.getItem('initialized'))
.then(flag => {
console.log(flag);
});
Функция возвращает Promise, что позволяет вкладывать цепочки друг в друга без потери последовательности.
Последовательность операций может формироваться динамически, например на основе массива ключей.
const keys = ['a', 'b', 'c'];
let chain = Promise.resolve();
keys.forEach(key => {
chain = chain.then(() => {
return localForage.setItem(key, `value-${key}`);
});
});
chain.then(() => {
return localForage.keys();
}).then(allKeys => {
console.log(allKeys);
});
Здесь цепочка строится итеративно, что позволяет гибко управлять количеством шагов.
При необходимости получить данные по очереди, а не параллельно, используется аналогичная техника построения цепочки.
const keys = ['user', 'settings', 'cache'];
let result = {};
let chain = Promise.resolve();
keys.forEach(key => {
chain = chain.then(() => {
return localForage.getItem(key);
}).then(value => {
result[key] = value;
});
});
chain.then(() => {
console.log(result);
});
Такой подход гарантирует, что каждое чтение завершится до начала следующего.
Линейная структура промисов упрощает логику, но снижает параллелизм. Операции, которые не зависят друг от друга, могут выполняться медленнее при строгой последовательности. В таких случаях цепочки следует использовать только там, где порядок действительно критичен: миграции данных, инкрементальные обновления, зависимые вычисления.
При этом сам механизм промисов в localForage остается стабильной основой для построения детерминированных сценариев работы с хранилищем, где каждая операция строго следует за предыдущей без нарушения состояния данных.