Благодаря @Adrian мне удалось найти способ избежать переполнения стека. Но до этого он был прав, и эта форма рекурсии должна была привести к переполнению стека. И поскольку вопрос «почему», его ответ принят. Это моя попытка «как» не сталкиваться с переполнением стека.
Тест 1
function f() {
return new Promise((resolve) => {
resolve();
}).then(f);
}
И используя await
:
Тест 2
async function f() {
return await Promise.resolve()
.then(f);
}
Я не уверен, можно ли в этом случае устранить Promise
!
И я знаю, что сказал нет setTimeout
, но это тоже интересный случай:
Тест 3
async function f() {
await new Promise(resolve => setTimeout(resolve, 0));
return f();
}
Это также не столкнется с переполнением стека.
В конце, чтобы дать вам контекст, почему я был заинтересован в этом; допустим, вы кодируете функцию для извлечения всех записей из DynamoDb AWS. Поскольку существует ограничение на количество записей, которые вы можете извлечь из DynamoDb за один запрос, вы должны отправить столько записей, сколько необходимо (с ExclusiveStartKey
), чтобы получить все записи:
Тест 4
async function getAllRecords(records = [], ExclusiveStartKey = undefined) {
let params = {
TableName: 'SomeTable',
ExclusiveStartKey,
};
const data = await docClient.scan(params).promise();
if (typeof data.LastEvaluatedKey !== "undefined") {
return getAllRecords(records.concat(data.Items), data.LastEvaluatedKey);
}
else {
return records.concat(data.Items);
}
}
Я хотел убедиться, что это никогда не столкнется с переполнением стека. Было нереально иметь такую огромную таблицу DynamoDb, чтобы на самом деле это проверить. Поэтому я придумал несколько примеров, чтобы убедиться в этом.
Сначала казалось, что тест № 4 действительно может столкнуться с переполнением стека, но мой тест № 3 показывает, что такой возможности нет (из-за await docClient.scan(params).promise()
).
[UPDATE]
Спасибо @Bergi, вот код для await
без Promise
:
Тест 5
async function f() {
await undefined;
return f();
}