1

I have a question regarding promises in nodeJS when using Rethindb. This code will give me the results from db first time anything changes, not more.

Lets say I start the script and add a row to the db, the new data will be printed in cmd. But if I add another one, nothing are shown. Something wrong with the way I use the promise? (and no, I dont want to use callback)

Thx!

PushData(r, table)
.then(res=>{
  console.log(res);
}


function PushData(r, table){
  return new Promise(function(resolve, reject){
    r.table(table)
    .changes()
    .run()
    .then(function(cursor){

      cursor.on("error", function(err) {
        reject(err)
      })
      cursor.on("data", function(data) {
        resolve(data);
      })
    });
  });
}
  • You can’t use a promise like this. Once a promise resolves once it is done. You should instead use a callback function to handle the data – vbranden Feb 25 '18 at 15:21
  • huh, so there is no fix or trix to make it work :P Im going for the callback solution rigth now, but I like the promises .then better, feels like the code are more structured that way – Owen Willsson Feb 25 '18 at 19:32
  • You can only resolve a promise once so a promise is not what you want for multiple changes that can happen minutes apart you might try rxjs which will give you methods like subscribe – vbranden Feb 25 '18 at 19:40
  • Will check that out, thx! – Owen Willsson Feb 25 '18 at 20:39
  • I'm not sure that he's trying to resolve a promise twice. Each time `PushData()` is called, a new promise is create and it's only fulfilled on the `resolve(data)` call, which happens only once and should trigger the corresponding `then()` call each time `PushData()` is called. Unless I'm overlooking something obvious, could the problem be somewhere else? – Miguel Calderón Mar 02 '18 at 09:11
  • You are rigth Miguel, this was my plan also, to create a new promise each time the function is called. But I'm going for the solution with callbacks now.... maybe I will try to understand the problem with this later. Thx – Owen Willsson Mar 06 '18 at 07:01
  • @MiguelCalderón my point was that the code listening to the data event from the cursor will call resolve multiple times and you can’t do that. A promise can only resolve or reject 1 time – vbranden Mar 30 '20 at 14:39

3 Answers3

0

Yes, you are conflating "promises" with "callbacks". A fundamental principle of a Promise is that it can only be fulfilled ONCE. After it has been resolved or rejected (the two ways it can be fulfilled), it cannot be operated on again.

Callbacks are not evil. This is the time to use them.

Chad Robinson
  • 4,575
  • 22
  • 27
0

A promise is only resolving to one value, and calling resolve() multiple times on a promise only return that value each time. That's not what you want.

What you want to do instead is to repeatedly call cursor.next() to get more values, one promise after another.

However, you may be also interested by another similar feature of ES6: the Asynchronous Iterator.

Here is my code for converting the cursor from rethinkdb into an async iterator:

import { $$asyncIterator } from 'iterall'

// Transform the cursor's stream into an Async Iterator.
function feedToAsyncIterator (p) {
  return {
    next () {
      return p.then(async cursor => {
        try {
          // See https://www.rethinkdb.com/api/javascript/next/
          const row = await cursor.next()
          return {value: row, done: false}
        }
        catch (e) {
          return {done: true}
        }
      })
    },
    [$$asyncIterator]() {
      return this
    }
  }
}

const myChangeFeed = r.table('myTable').changes().run(db)

// You can enumerate the changes from inside an async function this way:
for await (const change of feedToAsyncIterator(myChangeFeed)) {
  console.log('change:', change)
}
Vincent Cantin
  • 16,192
  • 2
  • 35
  • 57
0

My understanding is you have an asynchronous function that you want to call twice. for example, you want to insert two rows to DB you will call the function twice.

const PushData = async (r, table) => {
    try {
        const res = await new Promise(function (resolve, reject) {
            r.table(table)
                .changes()
                .run()
                .then(function (cursor) {

                    cursor.on("error", function (err) {
                        reject(err)
                    })
                    cursor.on("data", function (data) {
                        resolve(data);
                    })
                });
        });
        return res
    } catch (error) {
        throw error
    }
}

var res1 = await PushData(r,table)
console.log("result 1 is ==> "+res1)
var res2 = await PushData(r,table)
console.log("result 2 is ==> "+res2)
Shyam
  • 307
  • 3
  • 4