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, но за привидно синхронни функции (без обратни извиквания), или дали други са намерили това за полезно.

Така че изглежда, че promisify прави това, но не с вложени функции, както бих искал.

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