В классе qooxdoo, у меня есть набор асинхронных методов, которые должны быть соединены (сериализованным):Использование Обещания в приложении qooxdoo
main: function() {
async1();
},
async1: function() {
var json = new qx.data.store.Json("http://...");
json.addListener("loaded", function(event) {
...
async2();
});
},
async2: function() {
// similar to async1
}
Поскольку число шагов растет, цепь становится трудно trace, и код становится нечитаемым. Что мы можем сделать, это переписать код с помощью Promises:
main: function() {
new Promise(this.async1)
.then(function() {
return new Promise(this.async2);
}).then(function() {
return new Promise(this.async3);
}).catch(...);
},
async1: function(resolve, reject) {
var json = new qx.data.store.Json("http://...");
json.addListener("loaded", function(event) {
...
resolve();
});
},
async2: function(resolve, reject) {
// similar to async1
}
Это прекрасно работает, но только до тех пор, пока добавить некоторую реальную логику. Помните, что это класс qooxdoo с большим количеством материалов, инкапсулированных в this
. Но вдруг оказывается, что оба метода async * и анонимные функции, используемые в then() и catch(), имеют свой this
контекст, привязанный к window
, глобальному объекту. Для того, чтобы иметь возможность использовать фактические this
, мы можем выполнить пересвязывание:
main: function() {
new Promise(this.async1.bind(this))
.then(function() {
this.doSomeStuff();
return new Promise(this.async2.bind(this));
}.bind(this)).then(function() {
return new Promise(this.async3.bind(this));
}.bind(this)).then(function() {
this.doSomeFinalStuff();
}.bind(this)).catch(function() {
this.doStuffOnError();
}.bind(this));
},
async1: function(resolve, reject) {
this.doOtherStuff();
var json = new qx.data.store.Json("http://...");
json.addListener("loaded", function(event) {
...
resolve();
});
}
Это, наконец, работает, но Doh, некрасиво это код! Есть ли способы избавиться от этих ручных привязок? Почему не неявно связаны при ссылке this.async1
, метод экземпляра?
Просто наблюдение: если вам нужно вызвать длинную цепочку функций, независимо от того, асинхронны они или нет, я думаю, что есть хороший шанс, что в вашем общем дизайне что-то не так. (Возможно, я ошибаюсь, конечно, я не видел код.) Что касается функций, которые не связаны по умолчанию: это означает, что значение по умолчанию предотвратит прохождение несвязанных функций вокруг - необходимое для функционального стиля программирования - нет способ un-bind функции. И, кстати, вам нужен последний вызов 'bind()' выше, если вы используете переменную 'self', как это предлагается в принятом ответе? – user625488
Я видел необходимость такой последовательности асинхронных вызовов, когда вам нужно несколько ресурсов, предоставленных сервером для выполнения операции. Я бы сделал это, чтобы упаковать всю логику в одну функцию, которую я передал бы как обратный вызов для всего, что нужно получить асинхронно. Эта функция сначала проверит, соблюдены ли все предварительные условия, затем выполните все вычисления. IMO, если возможно, переключение на такую структуру кода значительно улучшило бы удобочитаемость - вместо того, чтобы иметь связанную с ним логику, опрыскиваемую множеством функций, у вас есть все в одном месте. – user625488
Кроме того, вы можете использовать структуру, основанную на событиях, вместо того, чтобы передавать обратные вызовы, у вас есть обратные вызовы, в которых вы регистрируете обработчик событий. Это все равно улучшит структуру кода, ИМО. С помощью простых обещаний вы упускаете возможность использовать описательные имена функций для документирования намерений. С событиями вы получаете две возможности для документации: имя события и имя обработчика. – user625488