Forwarded from S0ER
Promise.race
Всем привет, на связи Марго @devmargooo и сегодня я расскажу вам про Promise.race.🏎 Promise.race принимает в качестве аргумента массив промисов и возвращает результат того промиса, который завершится первым. Значит ли это, что после завершения Promise.race можно просто забыть про те промисы, которые проиграли гонку? Оказывается, нет. В 2017 году была описана интересная утечка памяти в Promise.race https://github.com/nodejs/node/issues/17469#issuecomment-685216777. Эта утечка интересна не сама по себе (мне кажется, Promise.race не так часто используют), а тем, что она представляет собой очень показательный пример утечки памяти в js через замыкания. Рассмотрим следующие тезисы.
1. Промис сохраняет свой результат все время, которое он живет.
Некоторые разработчики считают, что если мы не используем результат, который вернул промис, то он освободит память сразу после того, как промис завершится. Это не так! Результат промиса сохраняется в его внутреннем свойстве result все время, пока живет (= ссылочно доступен) сам промис.
2. Также, если промис зарезолвился, это еще не значит, что данные внутри его функции-исполнителя (функция, которую передали в конструктор промиса) больше не удерживаются в памяти. Нет, они могут удерживаться в памяти, например, если внутри исполнителя был setTimeout.
3. Рассмотрим следующий код и попробуем память, когда из памяти будет удален “super string”.
В данном случае neverResolve завис в памяти, а с ним и весь родительский промис p. Результат промиса resolveString сохранился как внутренее свойство result объекта p. Если “super string” - это тяжелые данные, то мы получим существенную утечку памяти. По всей видимости, механизм утечки памяти в Promise.race аналогичен вышеизложенному.
Всем привет, на связи Марго @devmargooo и сегодня я расскажу вам про Promise.race.🏎 Promise.race принимает в качестве аргумента массив промисов и возвращает результат того промиса, который завершится первым. Значит ли это, что после завершения Promise.race можно просто забыть про те промисы, которые проиграли гонку? Оказывается, нет. В 2017 году была описана интересная утечка памяти в Promise.race https://github.com/nodejs/node/issues/17469#issuecomment-685216777. Эта утечка интересна не сама по себе (мне кажется, Promise.race не так часто используют), а тем, что она представляет собой очень показательный пример утечки памяти в js через замыкания. Рассмотрим следующие тезисы.
1. Промис сохраняет свой результат все время, которое он живет.
Некоторые разработчики считают, что если мы не используем результат, который вернул промис, то он освободит память сразу после того, как промис завершится. Это не так! Результат промиса сохраняется в его внутреннем свойстве result все время, пока живет (= ссылочно доступен) сам промис.
2. Также, если промис зарезолвился, это еще не значит, что данные внутри его функции-исполнителя (функция, которую передали в конструктор промиса) больше не удерживаются в памяти. Нет, они могут удерживаться в памяти, например, если внутри исполнителя был setTimeout.
3. Рассмотрим следующий код и попробуем память, когда из памяти будет удален “super string”.
const resolveString = new Promise((resolve) => resolve("super string"));
const neverResolve = new Promise(() => {});
const promises = [resolveString, neverResolve];
const p = new Promise((resolve, reject) => {
for (const promise of promises) {
Promise.resolve(promise).then(resolve, reject);
}
});
В данном случае neverResolve завис в памяти, а с ним и весь родительский промис p. Результат промиса resolveString сохранился как внутренее свойство result объекта p. Если “super string” - это тяжелые данные, то мы получим существенную утечку памяти. По всей видимости, механизм утечки памяти в Promise.race аналогичен вышеизложенному.
GitHub
`Promise.race` lead to memory leak · Issue #17469 · nodejs/node
Version: v9.2.0 and v8.9.1, probably other version also affected Platform: linux Subsystem: - I run this code inside docker with -m 100m --memory-swap 100m , and then the program crash after few se...
🤡3❤2👍2
