Я работаю с ReactJS, и мне нужно создать массив для вставки данных, сохранить их в localStorage и просмотреть позже. Сначала я создаю массив с помощью this.subscriptionsList = [];, а затем использую этот метод для извлечения данных.
fetchNow = async (token, nextToken) => {
fetch("somewebsite")
.then(( unformattedData ) => {
return unformattedData.json();
})
.then(( webData) => {
for(let i = 0; i < webData.length; i++){
this.subscriptionsList.push("someData");
}
if (webData.hasOwnProperty('token')){
this.fetchNow(token, webData.token);
}else{
return;
}
})
}
Функция не завершена, так как это не главная тема моего вопроса. Он отлично работает и передает правильные данные.
Я получаю данные с помощью этого метода:
this.fetchNow(response.accessToken, "")
.then( () => {
console.info(this.subscriptionsList);
console.info(JSON.stringify(this.subscriptionsList));
localStorage.setItem("subscriptionsList", JSON.stringify(this.subscriptionsList));
//console.info(JSON.parse(localStorage.getItem("subscriptionsList")));
})
Проблема возникает при попытке использовать JSON.stringify. Выполнение console.info(this.subscriptionsList) печатает объект массива со всеми данными внутри него, как и ожидалось. Однако, когда я иду делать console.info(JSON.stringify(this.subscriptionsList)), он возвращает []. Кроме того, при печати самого объекта свойство length: 125, но при выполнении console.info(this.subscriptionsList.length) оно возвращает 0, а при доступе с использованием this.subscriptionsList[0] возвращает undefined. Я читал спецификации, и похоже, что JSON.stringify должен работать с массивом javascript. Мне не хватает чего-то конкретного, или это просто недоступно с JSON.parse?
https://gyazo.com/72aafe248ef61649a38c06d03fb3d830
https://gyazo.com/c2690b4392774fe4a98254a4d15f3a32
https://gyazo.com/e0793b5ec05da4259e16100f275da414
Не уверен, не могли бы вы попытаться сохранить this.subscriptionsList в локальной переменной и выполнить с ней операцию.
Я думал, что знаю, в чем проблема, пока вы не сказали, что логирование свойства length показывает другое значение, чем наблюдение свойства length, что практически невозможно. Вы в этом уверены?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вам нужно возвращаться цепочки обещаний в fetchNow, иначе вы не сможете подключиться к ней позже, когда будете пытаться. Вам также нужно будет подключить к return рекурсивный fetchNow, вызываемый внутри fetchNow, если вы хотите, чтобы он также был связан цепочкой:
fetchNow = (token, nextToken) => {
return fetch("somewebsite")
.then(( unformattedData ) => {
return unformattedData.json();
})
.then(( webData) => {
for(let i = 0; i < webData.length; i++){
this.subscriptionsList.push("someData");
}
if (webData.hasOwnProperty('token')){
return this.fetchNow(token, webData.token);
}
})
}
Функции async не делают асинхронные операции волшебным образом синхронными. Они (1) возвращают обещания и (2) разрешают ключевое слово await. Но поскольку вы не используете await, нет необходимости, чтобы fetchNow был async, а поскольку цепочка fetch уже является Promise, вы можете вернуть ее напрямую без async.
Если вы делать хотите использовать async и await, это сделает код более плоским и понятным:
fetchNow = async (token, nextToken) => {
const response = await fetch("somewebsite");
const webData = await response.json();
for(let i = 0; i < webData.length; i++){
this.subscriptionsList.push("someData");
}
if (webData.hasOwnProperty('token')){
await this.fetchNow(token, webData.token);
}
// async function will automatically return a Promise that resolves when the end is reached
}
Согласно комментарию @Jimmy console.info(this.subscriptionsList) prints an array object with all the data inside of it as expected, это не проблема с цепочкой обещаний.
Это связано с нелогичной реализацией console.info - он регистрирует объект жить, а не объект, как это было было, когда он был зарегистрирован.
См. Здесь: stackoverflow.com/questions/24175017/… (это не ограничивается Chrome, еще много вопросов по этой проблеме)
Сначала я тоже думал об этом, но когда я иду распечатать объект, это полный массив. Я все еще что-то упускаю?
@Jimmy console.info не интуитивно возвращает объект жить, а не объект на момент регистрации. Если вы сделаете stringify объект заранее, он будет более точно представлять содержимое объекта в данный момент времени.
Вот что происходит ... console.info(JSON.stringify(something)) делает то, что сериализует непосредственное значение и печатает сериализованную ссылку. (Другими словами, он создает клонированную копию и печатает клонированную копию, а не исходную ссылку, которую он не будет ждать поднятого / измененное значение). Что делает console.info(something), так это то, что он обращается к исходному значению и печатает фактический результат (измененный / поднятый), а не немедленный результат. Поскольку ваш метод является асинхронным, вы можете четко это заметить. Вы можете подождать, пока не будет выполнен вызов asyc, затем вы можете отправить фактическую переменную в localStorage. (Обратите внимание, что даже локальное хранилище хранится как сериализованные значения)
Изменить 1: -
let onComplete = (subscriptionsList) => {
console.info(JSON.stringify(subscriptionsList));
localStorage.setItem("subscriptionsList", JSON.stringify(subscriptionsList));
//console.info(JSON.parse(localStorage.getItem("subscriptionsList")));
}
fetchNow = async (token, nextToken, onComplete) => {
fetch("somewebsite")
.then(( unformattedData ) => {
return unformattedData.json();
})
.then(( webData) => {
for(let i = 0; i < webData.length; i++){
this.subscriptionsList.push("someData");
}
if (webData.hasOwnProperty('token')){
this.fetchNow(token, webData.token);
}else{
onComplete(this.subscriptionsList);
return;
}
})
}
this.fetchNow(response.accessToken, "", onComplete)
.then( () => {
console.info("direct call ", this.subscriptionsList);
})
Я действительно не понимаю, о чем вы говорите, поскольку я не слишком знаком с подъемом и т. д. В javascript. Насколько я понимаю, вы говорите, что каким-то образом массив становится пустым? Однако это не так. В конечном результате должны быть все данные. Я включил скриншоты в свой исходный пост для получения более подробной информации.
@Jimmy попробуйте пример кода в edit1, но не тестировал его. Все, что вам нужно сделать, это дождаться завершения асинхронного вызова.
Я вижу, что вы и CertainPerformance высказали то же самое, но я считаю, что его ответ поможет им в будущем больше, поскольку он демонстрирует важность цепочки обещаний, поэтому я принял его ответ. Однако ваш ответ в значительной степени демистифицирует ситуацию и также очень важен.
Не могли бы вы скриншот структуры объекта