3

I am trying to understand why these console.log statements behave differently. I expect them to behave the same:

Using Node 7. Consider the following cases:

1. Promise.resolve(object)

Promise.resolve handles objects as I'd expect:

Promise.resolve({ a: `hello` }).then(console.log) // { a:'hello' }

2. Directly console.log a class instance from a library.

If I store an Osmosis instance I can console.log it:

const osmosis = require(`osmosis`)
console.log(new osmosis.get(url)) 
/* { prev:                                                                                                                                                                   
     { instance: Osmosis:1,                                                                                                                                                 
     name: 'get',                                                                                                                                                         
     args: [ 'http://www.google.com', ,  ],                                                                                                                               
     getURL: [Function: getURLArg],                                                                                                                                       
     url: 'http://www.google.com',                                                                                                                                        
     params: undefined,                                                                                                                                                   
     cb: [Function: Get],                                                                                                                                                 
     next: [Circular] } }
*/

3. Promise.resolve(class instance)

But if I try to resolve an Osmosis instance I don't see parity:

Promise.resolve(new osmosis.get(url)).then(console.log) // nothing

What's going on here? Am I misunderstanding something about Promise.resolve()...? Or console.log?

Why doesn't [3] log the same as [2], given the behavior in [1]?

Context: I don't think my immediate practical goals matter to answering this question. But here you go just in case. I don't see how anything about the library itself should affect the output of the final example. Here's the docs on that new osmosis.get() though: http://rchipka.github.io/node-osmosis/Osmosis.html#toc1__anchor

new osmosis.get(url) doesn't perform an async http request. It instantiates an instance of the scraper, which can be built up with a set of declarative instructions and told to "run" at some arbitrary later time.

I want to be able to build this set of instructions in a promise chain for several reasons.

The main one is that it would be the easiest way to break up the instruction definitions into different functions that are easier to test and understand. e.g. instead of osmosis.get(url).set({some stuff}).find(@something), I'd like to:

function defineSearch(instance){
  return instance.set({some stuff})
}

function definePath(instance) {
  return instance.find(@something)
}

Promise.resolve(new osmosis.get(url))
  .then(defineSearch)
  .then(definePath)
  .then(instance => instance.run())
Aurora0001
  • 13,139
  • 5
  • 50
  • 53
Joseph Fraley
  • 1,360
  • 1
  • 10
  • 26
  • What are you actually trying to accomplish by wrapping an object in `Promise.resolve()`? If you're hoping it will wait until some async operation is done, that is not how promises work. In this case, wrapping your operation in `Promise.resolve()` is not really helping you in any way. – jfriend00 Nov 21 '16 at 09:47
  • I've add some context above, if it helps. But in the case of this question I am literally only trying to understand why that console.log prints empty. – Joseph Fraley Nov 21 '16 at 10:28
  • http://stackoverflow.com/questions/22519784/how-do-i-convert-an-existing-callback-api-to-promises – Benjamin Gruenbaum Nov 21 '16 at 14:08
  • @Benjamin Gruenbaum but why can I directly `console.log` a new instance, but never see the instance passed on via `Promise.resolve`? It's not a question of callbacks. I have direct, immediate, synchronous access to the `new osmosis` instance outside the `Promise.resolve` context. – Joseph Fraley Nov 21 '16 at 18:25
  • Just in case... *catch* the call to `osmosis`... maybe `osmosis.get` is throwing an exception so does not reach the `then()` clausule – Manu Artero Nov 21 '16 at 19:24
  • @Manu that's no longer an issue with node. It will log unhandled rejections. – Benjamin Gruenbaum Nov 21 '16 at 20:15

1 Answers1

2

The documentation is horrible and uses techniques that are rather unconventional. What new osmosis.get(url) returns is not an Osmosis instance but a Command one. And those do have a then method.

When you pass something to Promise.resolve, it is tested for being a thenable or not, and if it looks like a promise it is tried to be assimilated: a callback is passed into the then method which will resolve the new promise.

So when you do Promise.resolve(new osmosis.get(url)), you get back an unresolved promise that will fulfill when the then callback is called (which happens when you run the command). In your case, it never does.

The solution to your particular problem is not to use promises at all (since you're not doing anything asynchronous):

definePath(defineSearch(new osmosis.get(url))).run())

but you probably should also report a bug that Commands look like promises with being properly thenable, which breaks a lot of things in ES6.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Yes, the duck-typing bug is what I wasn't seeing. You're right that I cant just pass the instance through a series of functions, but it looks like like garbage and I was hoping to avoid it. It's true that I am not in fact doing anything asyncronous, but the promise chain naturally describes what it intuitively seems is happening when the scraper starts (just without actually starting it). Thanks a lot! (yeah those docs are drek) – Joseph Fraley Nov 21 '16 at 22:43
  • For proof this answer is correct: const x = new osmosis(); x.then = null; Promise.resolve(x).then(console.log) // everything works – Joseph Fraley Nov 22 '16 at 17:35