Я пытаюсь понять, как работают промисы, но не могу заставить работать свой фрагмент кода.
class Lights {
constructor(delay) {
this.blue = 0;
this.green = 0;
this.red = 0;
this.delay = delay;
}
fadeIn(color, i) {
var self = this;
return new Promise(function(resolve, reject) {
setTimeout(function () {
self[color] = i;
console.info(self[color]);
i+=5;
if (i <= 255) {
self.fadeIn(color, i);
}
resolve(self);
}, self.delay);
});
}
fadeOut(color, i) {
var self = this;
return new Promise(function(resolve, reject) {
setTimeout(function () {
self[color] = i;
console.info(self[color]);
i-=5;
if (i >= 0) {
self.fadeIn(color, i);
}
resolve(self);
}, self.delay);
});
}
}
var lights = new Lights(50);
lights.fadeIn("blue", 0).then(
lights.fadeOut("blue", 255)
);
Вот jsFiddle кода.
Идея кода состоит в том, чтобы установить синий цвет от 0 до 255 и Then от 255 до 0. Как я могу это сделать?
Чтобы прояснить, ваш then ожидает, что функция будет вызываться, когда она будет завершена, но то, что вы делаете, - это выполнение fadeOut и возвращение обещания от этого, поэтому оно выполняется до того, как это должно было произойти.
Добавление к предыдущим комментариям; ваши методы fadeIn и fadeOut не дожидаются завершения затухания, чтобы выполнить обещание, поэтому fadeOut начнет работать до завершения fadeIn. Попробуйте заменить self.fadeIn(color, i); на return resolve(self.fadeIn(color, i));, то же самое касается метода fadeOut.
Также обратите внимание, что вы вызываете fadeIn из своего метода fadeOut, вероятно, не то, что вам нужно. Обновленная рабочий пример: jsfiddle.net/87haj6x9



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


Вы выполняете рекурсивные вызовы, поэтому при последнем вызове то, что вы разрешаете, не является разрешением в вашем первом обещании, на котором вы вызываете then, чтобы вы могли сохранить это первое разрешение в одном свойстве вашего класса, а затем вызвать его.
class Lights {
constructor(delay) {
this.blue = 0;
this.green = 0;
this.red = 0;
this.delay = delay;
this.fadeInResolve = null;
this.fadeOutResolve = null;
}
fadeIn(color, i) {
return new Promise((resolve, reject) => {
if (!this.fadeInResolve) {
this.fadeInResolve = resolve
}
setTimeout(() => {
this[color] = i;
console.info(this[color]);
i += 5;
if (i <= 255) this.fadeIn(color, i);
else this.fadeInResolve(this)
}, this.delay);
});
}
fadeOut(color, i) {
return new Promise((resolve, reject) => {
if (!this.fadeOutResolve) {
this.fadeOutResolve = resolve
}
setTimeout(() => {
this[color] = i;
console.info(this[color]);
i -= 5;
if (i >= 0) this.fadeOut(color, i);
else this.fadeOutResolve(this)
}, this.delay);
});
}
}
var lights = new Lights(50);
lights.fadeIn("blue", 0).then(() => {
console.info('Fade in done')
lights.fadeOut("blue", 255).then(() => {
console.info('Fade out done')
})
});Я использовал ваш код для создания этот jsFiddle. Я попытался сделать одно затухание, затем одно затухание, затем снова затухание с другим цветом и, наконец, затухание. Но затухание никогда не запускается, подскажите почему?
Поскольку вы должны установить для него значение null после его разрешения, вы также можете использовать async / await вместо всех тех, которые затем jsfiddle.net/hjx1az4n/1
Возможно ли внутри await запустить два fadeIn (которые могут разрешиться в разное время, дождаться разрешения обоих и затем выполнить другое действие?
Конечно jsfiddle.net/hjx1az4n/3, но вам нужно настроить разные свойства для каждого цвета
Большое спасибо, это было очень полезно
Рад, что смог помочь.
Promise.prototype.then() должен принимать функцию обратного вызова, и рекурсия не ждет. Рассмотрим этот код, который можно использовать для того же:
//promisify :)
function timer(delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, delay);
});
}
class _Modulator {
constructor(_resolution = 255, _delay = 5) {
/* assert resolution and delay > 0; */
this._resolution = _resolution;
this._delay = _delay;
this._counter = 0;
this._running = false;
}
start() {
console.info("timer start");
this._running = true;
this._start();
}
_start() {
return timer(this._delay).then(() => {
if (this._running === true) {
this._counter += 1;
console.info("tick");
this._onTick();
/* care should be taken to ensure this will always catch, e.g.,
* correcting init
*/
if (this._counter === this._resolution) {
this._counter = 0;
this._onCycle();
}
this._start();
}
});
}
stop() {
this._running = false;
console.info("timer stopped");
}
_onTick() {
console.info("tick handle: %s", this._counter);
}
_onCycle() {
console.info("new cycle");
}
}
class UpDownModulator extends _Modulator {
constructor(_resolution = 255, _delay = 5) {
super(_resolution, _delay);
this._dir = 1;
}
_onTick() {
console.info("tick handle: %s", this.getCounter());
}
_onCycle() {
this._toggleDirection();
console.info("new cycle: going %s", this.getDirection());
}
_toggleDirection() {
this._dir ^= 1;
}
getCounter() {
return this._dir
? this._counter
: this._resolution - this._counter;
}
getDirection() {
return this._dir ? "up" : "down";
}
}
let c = new UpDownModulator();
c.start();Вы можете создать класс ColorFader, который зависит от модулятора, и наблюдать за ним. Это создает чистые абстракции, соответствующие SRP.
Надеюсь, это поможет!
lights.fadeIn("blue", 0).then(() => lights.fadeOut("blue", 255));В противном случае ваше затухание будет выполнено до того, как ваше обещание будет выполнено.