2015-12-05 3 views
7

Я сталкиваюсь с предупреждением Promise о неразрывной цепочке обещаний («обещание было создано в обработчике, но не было возвращено из него»). Я новичок в Promises и подозреваю, что я использую мышление, не основанное на событиях, когда я не должен быть. Но я не уверен, как действовать дальше. Все это находится в проекте nodejs.Завершение цепочки Promise

Я взаимодействую с сервером ZWave, чтобы включать и выключать источники света. Это взаимодействие принимает форму отправки HTTP-запросов на сервер, который управляет сетью ZWave. Я использую Promises из-за асинхронного взаимодействия с HTTP.

На одном уровне моей программы я следующий метод класса определяется:

ZWave.prototype.onOff = function (nodeNumber, turnOn) { 
var self = this; 
var level = turnOn ? 255 : 0; 

return new Promise(function (resolve, reject) { 
    self.requestAsync(sprintf('/Run/devices[%d].instances[0].commandClasses[0x20].Set(%d)', nodeNumber, level)) 
    .then(function (value) { 
     resolve(value == 'null'); 
    }) 
    .catch(function (error) { 
     reject(error); 
    }); 
}); 

};

Метод метода requestAsync - тот, который фактически взаимодействует с сервером ZWave. Концептуально, в onOff() Я пытаюсь превратить определенный свет, идентифицированный этим.nodeNumber, как включенным, так и выключенным, а затем возвращать результат этого запроса.

ONOFF() вызывается из метода класса Switch, представляющий особый свет, следующим образом:

this.onOff = function(turnOn) { 
    var state = turnOn ? 'ON' : 'OFF'; 

    var self = this; 

    zWave.onOff(this.nodeNumber, turnOn) 
    .then(function() { 
     winston.info(sprintf('%s: turned %s', self.displayName, state)); 
     return true; 
    }) 
    .catch(function(error) { 
     winston.info(sprintf('%s: error while turning %s => %s', self.displayName, state, error)); 
     return false; 
    }); 
} 

«возвращает истину» и «возвращать ложные» заявления моя попытка положить конец цепи Promise , Но он не работает, и я все еще получаю предупреждение.

Это наводит на меня как конкретный пример более общей проблемы: как вы переходите от модели на основе Promise к традиционному блокирующему коду?

Редактировать

Отвечая на несколько вопросов от комментариев ...

Я использую Bluebird.

zWave.onOff() возвращает обещание.

Switch.onOff() и zWave.onOff() - различные функции в отдельных классах.

Весь код - это javascript.

Edit 2

Я считаю, что я реализовал предложения jfriend00, хотя я включил обработчик .catch() в zWave.onOff() функции, но я все еще получаю ту же ошибку необработанного обещания:

ZWave.prototype.onOff = function (nodeNumber, turnOn) { 
    var self = this; 
    var level = turnOn ? 255 : 0; 

    return self.requestAsync(sprintf('/Run/devices[%d].instances[0].commandClasses[0x20].Set(%d)', nodeNumber, level)) 
     .then(function(value) { 
      resolve(value == 'null'); 
     }) 
     .catch(function(error) { 
      reject(error); 
     }); 
}; 

и

// function inside Switch class 
this.onOff = function(turnOn) { 
    var state = turnOn ? 'ON' : 'OFF'; 
    var self = this; 

    return zWave.onOff(this.nodeNumber, turnOn).reflect() 
     .then(function() { 
      winston.info(sprintf('%s: turned %s', self.displayName, state)); 
      return true; 
     }) 
     .catch(function(error) { 
      winston.info(sprintf('%s: error while turning %s => %s', self.displayName, state, error)); 
      return false; 
     }); 
} 

Вот текст предупреждения:

Warning: a promise was created in a handler but was not returned from it at ZWave.requestAsync (/home/mark/XmasLights/zWaveRequest.js:19:12) at ZWave.onOff (/home/mark/XmasLights/zWaveRequest.js:93:17) at onOff (/home/mark/XmasLights/switch.js:42:22) at updateCron (/home/mark/XmasLights/switch.js:80:18) at dailyUpdate (/home/mark/XmasLights/app.js:196:21) at /home/mark/XmasLights/app.js:134:58 at processImmediate [as _immediateCallback] (timers.js:383:17)

Прошу прощения за форматирование предупреждения, я не могу получить stackoverflow для правильного разделения строк.

+1

Используете ли вы библиотеку Promise, например 'q' или' bluebird', или это просто простые обещания узла? Возможные ответы сильно различаются. –

+0

Не могли бы вы также добавить метод requestAsync? – acupajoe

+0

@acupajoe: он не сможет, если он импортирует его через 'var requestFn = bluebird.promisifyAll (require ('some module'))' –

ответ

6

В соответствии с документами Bluebird это предупреждение возникает, когда вы создаете обещание в области обещания, но вы ничего не возвращаете из этой области Promise.Bluebird обнаруживает, что вы создаете обещание внутри обработчика обещаний, но ничего не возвращали от этого обработчика, который потенциально является несвязанным обещанием, когда он должен быть связан с другими обещаниями. Вы можете прочитать, что они говорят о проблеме here.

В коде вы раскрытые, вы все, что, как примеры Bluebird шоу в их документе не показывать, но я бы предположил, что один вопрос здесь:

ZWave.prototype.onOff = function (nodeNumber, turnOn) { 
    var self = this; 
    var level = turnOn ? 255 : 0; 
    return new Promise(function (resolve, reject) { 
     self.requestAsync(sprintf('/Run/devices[%d].instances[0].commandClasses[0x20].Set(%d)', nodeNumber, level)).then(function (value) { 
      resolve(value == 'null'); 
     }).catch(function (error) { 
      reject(error); 
     }); 
    }); 
}; 

Где бы лучше избегать антишаблона и делать это:

ZWave.prototype.onOff = function (nodeNumber, turnOn) { 
    var level = turnOn ? 255 : 0; 
    return this.requestAsync(sprintf('/Run/devices[%d].instances[0].commandClasses[0x20].Set(%d)', nodeNumber, level)).then(function (value) { 
     return(value == 'null'); 
    }); 
}; 

Там нет необходимости создавать новое обещание здесь, потому что у вас уже есть, что вы можете просто вернуться. Вы можете больше узнать об исключении типа анти-шаблона, который вы использовали here.


И еще один возможный вопрос здесь, где вы создаете возвращаемое значение обещания, но не вернуть его из метода this.onOff. Вы явно сделали return true; или return false; от ваших обработчиков .then(), но тогда вы никогда ничего не делаете с этим возвращаемым значением, поскольку последующие обработчики .then() не выполняются, и само обещание не возвращается.

this.onOff = function(turnOn) { 
    var state = turnOn ? 'ON' : 'OFF'; 

    var self = this; 

    zWave.onOff(this.nodeNumber, turnOn) 
    .then(function() { 
     winston.info(sprintf('%s: turned %s', self.displayName, state)); 
     return true; 
    }) 
    .catch(function(error) { 
     winston.info(sprintf('%s: error while turning %s => %s', self.displayName, state, error)); 
     return false; 
    }); 
} 

Я предложил бы изменить это, чтобы вернуть обещание, как это:

this.onOff = function(turnOn) { 
    var state = turnOn ? 'ON' : 'OFF'; 

    var self = this; 

    // ===== add return statement here 
    return zWave.onOff(this.nodeNumber, turnOn) 
    .then(function() { 
     winston.info(sprintf('%s: turned %s', self.displayName, state)); 
     return true; 
    }) 
    .catch(function(error) { 
     winston.info(sprintf('%s: error while turning %s => %s', self.displayName, state, error)); 
     return false; 
    }); 
} 

Это, а затем обеспечивает true или false возвращаемое значение обещание вызвавшей .onOff(). Или, если вам не нужно получать эти возвращаемые значения, вы можете удалить операторы return true и return false, чтобы не было никаких обещаний.

This strikes me as a specific example of a more general issue: how do you move from a Promise-based model to traditional blocking code?

Вы не пишете традиционный код блокировки для асинхронных операций. Асинхронные операции являются асинхронными и никогда не будут традиционным блокирующим кодом. Посылы предоставляют намного больше структуры для управления и координации асинхронных операций, но вам все равно придется писать код для них в асинхронном режиме. Просто написать этот асинхронный код с помощью обещаний просто проще.

Язык JS добавляет больше возможностей, таких как генераторы, и ждет, что вы можете использовать для этого. Вот короткая статья на эту тему: ES7 async functions.

+0

Очень полезно, спасибо! Я отправлю сообщение, когда попробую ваши предложения. Один вопрос, однако: второе предложение, похоже, не влечет за собой каких-либо изменений в коде, который вы сказали, я должен исправить. Что мне не хватает? –

+0

@MarkOlbert - В последнем блоке кода в моем ответе есть надпись 'return' перед' zWave.onOff() ', чтобы вернуть обещание. – jfriend00

+0

Duh! Тханкс, я пропустил это. –

Смежные вопросы