У меня есть две асинхронные функции, и у каждой есть обратный вызов setInterval.
Первый:
timer = null;
r = 0;
async function t() {
// return timer
if (timer) return(timer);
timer = setInterval(() => {
r += 10
if (r === 100) clearInterval(timer);
console.info('timer', timer, 'r', r)
}, 1000)
}
console.time('timer')
console.info(await t())
console.timeEnd('timer')
Второй:
timer1 = null;
r1 = 0;
async function t1() {
// clearInterval timer1
if (timer1) clearInterval(timer1);
timer1 = setInterval(() => {
r1 += 10
if (r1 === 100) clearInterval(timer1);
console.info('timer1', timer1, 'r1', r1)
}, 1000)
}
console.time('timer1')
console.info(await t1())
console.timeEnd('timer1')
Но когда я их запускал, они делали то же самое, такие же результаты, как показано ниже:
timer 18 r 10
timer 18 r 20
timer 18 r 30
timer 18 r 40
timer 18 r 50
timer 18 r 60
timer 18 r 70
timer 18 r 80
timer 18 r 90
timer 18 r 100
Второй вывод такой же, как и выше:
timer1 23 r1 10
timer1 23 r1 20
timer1 23 r1 30
timer1 23 r1 40
timer1 23 r1 50
timer1 23 r1 60
timer1 23 r1 70
timer1 23 r1 80
timer1 23 r1 90
timer1 23 r1 100
Мои вопросы:
return (timer), 2-й - это clearInterval(timer), но 1-й не возвращает timerId за интервал, а 2-й не возвращает clearInterval(timerId), тогда он должен генерировать новый timerId за интервал, верно? Почему?import React from 'react';
import PropTypes from 'prop-types';
function loadScript(url) {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.body.appendChild(script);
return new Promise((resolve) => {
if (script.readyState) { // IE
script.onreadystatechange = function change() {
if (script.readyState === 'loaded' || script.readyState === 'complete') {
resolve();
}
};
} else { // Others
script.onload = function load() {
resolve();
};
}
});
}
export default class LazyloadMap extends React.Component {
static propTypes = {
loading: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), // loading effects
url: PropTypes.string, // SDK url
onload: PropTypes.func, // load success
onfail: PropTypes.func, // load failed
}
static defaultProps = {
loading: 'Map was in loading', // string | ReactNode
url: 'http://api.map.baidu.com/api?v=2.0&ak=***************************&callback=initializeBMap',
onload: () => {},
onfail: (e) => { alert(`加载地图失败,请重试: ${e};`); },
}
static timer = null;
static record = 0;
static initialized() {
const timeout = 1e4;
return new Promise((resolve, reject) => {
if (
window.BMap &&
typeof window.BMap === 'object' &&
!('apiLoad' in window.BMap)
) {
resolve(window.BMap);
} else {
// if timer has been initialized, does create a new `timer`
// and clear it. Another way is just return the old `timer`,
// i have tried the diff ways, but i am very confusing with that
// so i sent this post, any one can help me? thanks in advanced.
if (LazyloadMap.timer) {
clearInterval(LazyloadMap.timer);
}
LazyloadMap.timer = setInterval(() => {
LazyloadMap.record += 10;
if (
window.BMap &&
typeof window.BMap === 'object' &&
!('apiLoad' in window.BMap)
) {
resolve(window.BMap);
clearInterval(LazyloadMap.timer);
}
if (LazyloadMap.record >= timeout) {
clearInterval(LazyloadMap.timer);
reject(new Error('加载超时, 请重试'));
}
}, 10);
}
});
}
state = {
loaded: false
}
async componentWillMount() {
const { url, onload, onfail } = this.props;
const onLoadSuccess = () => {
this.setState({
loaded: true,
}, () => {
onload && onload(window.BMap);
});
};
if (!window.BMap) {
try {
console.time('componentWillMount:await-load-Bmap-used');
await loadScript(url);
await LazyloadMap.initialized();
console.timeEnd('componentWillMount:await-load-Bmap-used');
onLoadSuccess(window.BMap);
} catch (e) {
onfail && onfail(e instanceof Error ? e : new Error(e));
}
} else {
onLoadSuccess(window.BMap);
}
}
render() {
return this.state.loaded ? this.props.children : this.props.loading;
}
}
// flag to records whether BMap SDK was initialized,
// if it did BMap will be an object
window.BMap = undefined;
// after loadScript(url) server does return `BMap` SDK, it returned following JavaScript code
// so i use a `timer` to listening `loaded` attribute
/* (function () {
window.BMap_loadScriptTime = (new Date).getTime();
window.BMap = window.BMap || {};
window.BMap.apiLoad = function () {
delete window.BMap.apiLoad;
if (typeof initializeBMap == "function") {
initializeBMap()
}
};
var s = document.createElement('script');
s.src = 'http://api.map.baidu.com/getscript?v=2.0&ak=**********************&services=&t=20180629105706';
document.body.appendChild(s);
})(); */
window.initializeBMap = LazyloadMap.initialized;<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src = "https://unpkg.com/[email protected]/prop-types.js"></script>Какова цель этого кода? Судя по всему, ничего полезного он не делает.
Вам не нужно строить обещание. Вот что делает для вас async
Похоже, что первое невозможно изменить, если по нему ударить несколько раз. Независимо от того, сколько раз ударил t(), он не запустит / не перезапустит таймер, но это не относится к t1(). Похоже, что по t1() можно нажимать несколько раз, и это «обновит» таймер. Он просто очищает старую и запускает новую. Что произойдет, если вы нажмете один из методов несколько раз, прежде чем он завершится?
Я бы сказал, что разница не имеет значения, поскольку оба кода не работают - вы никогда не выполняете обещание.
Разница проявится только в том случае, если вы действительно вызовете свои функции несколько раз. В вашем примере другой путь кода фактически никогда не используется.
@sjahan Я использовал это для React.Component с ленивой загрузкой третьего JS SDK. В этом компоненте он ожидает третьего события JS SDK loaded, поэтому я использовал таймер interval для ожидания третьего глобального объекта в SDK. Вы можете увидеть, что я сделал, на фотографиях отредактированного поста.
Просто говорю, но изображения кода - никогда не лучший способ поделиться кодом.
setInterval, безусловно, самый уродливый способ чего-то ждать. Разве загрузка BMap не дает вам обещания или хотя бы обратного вызова? Было бы нормально в 2018 году, когда вы делаете что-то асинхронно, вы возвращаете Promise.
@sjahan Да, ты прав. покажу вам мой код. и BMap также имеют функцию обратного вызова. Вы могли видеть это на самой нижней строчке.
@JosephMarikle новая версия фрагмента кода после редактирования сообщения. и очень ясно видеть, что я хочу делать.
@Vuchan, если есть функция обратного вызова, зачем ждать с setInterval? Когда вызывается ваша функция обратного вызова, можно было ожидать, что все готово к использованию. В противном случае этот обратный вызов initializeBMap был бы довольно глупым.
@sjahan Хотя это работает хорошо, но я думаю, ты до сих пор не знаешь, зачем я это делал. Я прошу прощения за это.



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


Ваши обещания никогда не сбываются ... Это нормально? : / Ваш код определенно странный, не могли бы вы объяснить, чего пытаетесь достичь? Это действительно могло помочь.