Есть ли у bluebird функция убеждения для переноса функций в промисы?

У меня есть объект функций. Эти функции не всегда полностью обещаны.

Например:

function helloWorld(string){
  if(string == "foo") throw new Error("string is foo")
  return aPromise(string)
}

Если string равно "foo", это вызовет ошибку, которая не будет обнаружена при вызове catch.

Я бы предпочел написать более чистый код, как указано выше, вместо этого:

function helloWorld(string){
  return Promise.resolve(){
    if(string == "foo") throw new Error("string is foo")
    return aPromise(string)
  }
}

Поэтому я создал эти функции, которые отображают объект и добавляют вложенные Promise.resolve.

makePromises: function(obj){
  return _.mapObject(obj, function(fn){
    return function(){
      var args = _.values(arguments)
      return Promise.resolve().then(function(){
        return fn.apply(null, args)
      })
    }
  })
},
makeNestedPromises:function(obj){
  return _.mapObject(obj, function(fn){
    return function(){
      var args = _.values(arguments)
      var value = fn.apply(null, args)
      return function(){
        var args = _.values(arguments)
        return Promise.resolve().then(function(){
          return value.apply(null, args)
        })
      }
    }
  })
}

Мне было интересно, существовало ли это уже изначально в bluebird, например promisifyAll, но для внешне синхронных функций (без обратных вызовов), или другие сочли это полезным.

Так что кажется, что обещание делает это, просто не с вложенными функциями, как хотелось бы.

var Promise = require("bluebird")

var concat = function(one, two){
  return Promise.resolve(one + " " + two)
}

var fns = {}

fns.hello = function(name, rank){
  if(name == "tom") throw new Error("tom unauthorized")
  return concat(name, rank)
}

Promise.promisifyAll(fns)

fns.helloAsync("tom", "developer")
  .catch(function(e){
    console.log(e)
  })

Вот что сломано:

var Promise = require("bluebird")

var concat = function(one, two){
  return Promise.resolve(one + " " + two)
}

var fns = {}

fns.hello = function(unauthorized){
  return function(name, rank){
    if(name == unauthorized) throw new Error("unauthorized")
    return concat(name, rank)
  }
}

Promise.promisifyAll(fns)

// here promisify thinks that the top level function should be a promise
fns.helloAsync("tom")("tom", "developer")
  .catch(function(e){
    console.log(e)
  })

person ThomasReggi    schedule 15.07.2015    source источник
comment
возможно обещание? github.com/petkaantonov/bluebird/blob/master/   -  person njzk2    schedule 15.07.2015
comment
Promise.resolve также может принимать значение, возвращаемое функцией, поэтому вы можете выполнить Promise.resolve(fn.apply(...)) для получения результата функции в виде обещания. Это, по крайней мере, устраняет ненужный .then   -  person NG.    schedule 15.07.2015
comment
Ваш второй фрагмент кажется синтаксической ошибкой. Вы имели в виду return Promise.resolve().then(function(){ …; return …; }) или return new Promise(function(resolve) { … resolve(…); })?   -  person Bergi    schedule 15.07.2015


Ответы (2)


Да, вы можете использовать для этого Promise.method:

var helloWorld = Promise.method(function helloWorld(string) {
  if(string == "foo") throw new Error("string is foo")
  return aPromise(string)
});

Вы должны использовать промисификацию только для функций с асинхронными обратными вызовами, она не работает с синхронными или возвращающими промис (даже если она перехватывает синхронные исключения).

person Bergi    schedule 15.07.2015
comment
К сожалению, не существует функции Promise.methodAll, которая могла бы обернуть все функции в объект. - person ThomasReggi; 15.07.2015
comment
@ThomasReggi: Promise.method предполагается использовать только в самом определении метода, а не обещать чужие методы. Каков ваш точный вариант использования? - person Bergi; 15.07.2015
comment
Проверьте ответ ниже. Мой вариант использования заключается в том, что я создаю функцию, которая использует промисы, и я не хочу оборачивать каждый вызов в Promise.resolve. - person ThomasReggi; 15.07.2015
comment
Это (Берги) правильное использование Promise.method. - person Benjamin Gruenbaum; 15.07.2015
comment
@ThomasReggi: Правильно, вы не хотите заключать каждый вызов в Promise.resolve, вы хотите заключать каждое определение, которое иногда выдает/возвращает синхронно, в Promise.method. - person Bergi; 15.07.2015

Я создал Promise.methodAll с необязательным параметром deep. ИспользованиеPromise.method из ответа @Bergi.

var Promise = require("bluebird")
var _ = require("underscore")

Promise.methodAll = function(obj, deep){
  return _.mapObject(obj, function(fn){
    if(!deep) return Promise.method(fn)
    return function(){
      var nestedFn = fn.apply(null, _.values(arguments))
      return Promise.method(nestedFn)
    }
  })
}

var concat = function(one, two){
  return Promise.resolve(one + " " + two)
}

var deep = {}

deep.authorize = function(unauthorized){
  return function(name, rank){
    if(name == unauthorized) throw new Error("unauthorized")
    return concat(name, rank)
  }
}

deep = Promise.methodAll(deep, true)

var normal = {}

normal.authorize = function(name, rank){
  if(name == "tom") throw new Error("tom unauthorized")
  return concat(name, rank)
}

normal = Promise.methodAll(normal)

normal.authorize("tom", "developer")
  .catch(function(e){
    console.log(e) //[Error: tom unauthorized]
  })

deep.authorize("tom")("tom", "developer")
  .catch(function(e){
    console.log(e) //[Error: unauthorized]
  })
person ThomasReggi    schedule 15.07.2015
comment
Суть Promise.method в том, что вы не должны создавать такие функции, которые лишь иногда возвращают промисы. Если функция асинхронная, она всегда должна возвращать обещание (и Promise.method может помочь в этом, упростив синтаксис). - person Bergi; 15.07.2015