Есть ли у Promise время, в конце концов, оно "отклонит" себя, если оно никогда не будет разрешено в течение определенного периода времени?
Это приходит мне в голову, потому что я написал небольшой тег сценария для загрузки сценария через обещание получения сценария от стороннего сервиса. Я думал, что если сторонняя служба будет постоянно загружаться, не отказываясь от результата, то что произойдет с этим обещанием? Есть ли способ обойти такую крайнюю ситуацию? является ли добавление тайм-аута для всего loadScript самым разумным способом сделать это?
function loaderScript(scriptUrl){
return new Promise(function (res, rej) {
let script = document.createElement('script');
script.src = scriptUrl;
script.type = 'text/javascript';
script.onError = rej;
script.async = true;
script.onload = res;
script.addEventListener('error',rej, { once: true });
script.addEventListener('load',res, { once: true });
document.head.appendChild(script);
})
}
loaderScript('https://...com').then(() => {...}).catch(() => { ... })
1 ответ
У Promise есть время
reject
само по себе, если его никогда не разрешается в течение определенного периода времени?
Обещания не имеют встроенного тайм-аута. Если ничто не разрешит или не отвергнет их, они останутся "ожидающими" навсегда.
Вы можете создать свой собственный тайм-аут, если хотите.
function loaderScript(scriptUrl) {
return new Promise(function(res, rej) {
const TIMEOUT = 5 * 1000;
let timer = setTimeout(function() {
rej(new Error("Script load timeout"));
}, TIMEOUT);
let script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.addEventListener('error', function(e) {
rej(e);
clearTimeout(timer);
});
script.addEventListener('load', function() {
res();
clearTimeout(timer);
});
script.src = scriptUrl;
document.head.appendChild(script);
})
}
Но браузеры имеют тайм-аут на запросы, которые они делают, поэтому вставка тега скрипта должна в конечном итоге привести к load
или же error
события, которые инициируются. Тайм-ауты браузера иногда могут быть длинными и не стандартными (они могут отличаться от одного браузера к другому), поэтому часто полезно добавить свой собственный тайм-аут, которым вы управляете.
Некоторые другие комментарии к вашему коду:
- Вам не нужно делать оба
.onError
и слушать заerror
событие. Выберите один или другой. - Вам не нужно использовать
once:true
, Во-первых, события load и error не будут вызваны более одного раза. Во-вторых, даже если они это сделали, это не причиняет вреда, потому что обещания разрешаются или отклоняются только один раз. Как только вы решили или отклонили его, они защелкиваются и вызываютres()
или жеrej()
не буду ничего делать после этого. - Всегда безопаснее установить
.src
свойство last после того, как все обработчики событий присоединены, поэтому нет никаких шансов пропустить какие-либо события. - Лучше отклонить с указанием причины, чтобы вызывающий абонент мог проверить, что могло произойти.