1

I am trying to implement a shopify api in node and want to call the post requests synchronously since i want to retrieve the product id after posting and store it in an array. I am making use of a library called deasync as a synchronous waiting loop. The script used to work before and suddenly stopped working. When i log my calls without the deasync loop, i see that responses are returned from shopify, however, when I'm running my script with the deasync loop, my identifier stays null, and the deasync loop keeps iterating. I am relatively new to asynchronous requests in node.js. The scope of my identifier variable seems correct. The only thing I can imagine for now is that the callback happens in a parallel node.js universe that is seperate from my while loop. Any help would be much appreciated, thx!

function postProduct(Store, product, variants) {

  var identifier = null;

  var post_data = {
    "product": product
  };


  Shopify.post('/admin/products.json', post_data, function(err, data, headers) {

    identifier = {
      id: data.product.id,
      price: data.product.price,
      variants: variants
    };

  });

  while(identifier === null) {
    require('deasync').runLoopOnce();
  }

  return identifier;
}
jo v
  • 302
  • 5
  • 14
  • You should not have synchronous I/O of any kind after the first tick. – Madara's Ghost Nov 26 '15 at 19:31
  • I got the idea from: http://stackoverflow.com/questions/21819858/how-to-wrap-async-function-calls-into-a-sync-function-in-node-js-or-javascript – jo v Nov 26 '15 at 19:40
  • 3
    Yeah, it's just really not a very good idea. – Madara's Ghost Nov 26 '15 at 19:43
  • @jov: Well, it's just that. An idea. With a proof of concept. Not something that should really be used unless you know exactly what you're doing. – Bergi Nov 26 '15 at 19:45
  • ok, thx for pointing that out, but in this case, any idea why the callback never seems to happen? – jo v Nov 26 '15 at 19:48
  • `deasync` uses undocumented `process._tickDomainCallback`... – vp_arth Nov 26 '15 at 20:00
  • just a guess, but maybe Shopify isn't properly setup? The docs say it takes a `shopOrigin` property. If that is invalid, the sdk might not be able to call your callback. You could try adding `{debug: true}` when calling `ShopifyApp.init` to see if there are any problems - https://docs.shopify.com/embedded-app-sdk/initialization - I would also add that you should avoid trying to do this synchonously and instead use something like async.js to get better control of the flow of execution in your app - embrace the async nature of node.js – Robbie Nov 26 '15 at 20:06
  • When I remove the deasync loop everything runs perfectly async, so this tells me Shopify is set up properly. The reason why I'm calling it synchronously is becasue i'm trying to fill an array with the product id's that are returned in the responses. The amount of calls I am making is dynamic and depends on the amount of products that are fed in. An array of all the product identifiers is finally stored using another api request to my own server. In the case of asynchronous requests, the identifiers will remain null.. – jo v Nov 26 '15 at 20:11
  • take a look to promises, anyway. – vp_arth Nov 26 '15 at 20:19

1 Answers1

3

All of this deasync solutions can't to be stable, because they are depend on internal engine implementation.

Just try to learn async way. It's really simple.

Simplified example with native Promise:

var products = [
  {Store: {}, product: {}, variant: {}},
  {Store: {}, product: {}, variant: {}},
];

Promise.all(products.map(postProduct)).then(function(identifiers){
  // use identifiers
});

function postProduct(data) {
  return new Promise(function(ok, fail){
    Shopify.post(...., function(){
       //...
       ok(identifier);
    });

  });
}
vp_arth
  • 14,461
  • 4
  • 37
  • 66
  • 1
    its not really a 'workaround'... just a better way of doing it – Robbie Nov 26 '15 at 20:28
  • interesting, will try and work with this. Was looking at the Async(https://github.com/caolan/async) library earlier, and seems very similar – jo v Nov 26 '15 at 20:32
  • `Promise` is native from `node v0.12`, `async` was created before `Promise` become a standard thing. My own way was [async](https://github.com/caolan/async) -> [Q promises](https://github.com/kriskowal/q) -> es6 `Promise` – vp_arth Nov 26 '15 at 20:41
  • 1
    i see async.js as a higher level utility belt - it offers a lot more than you get with promises – Robbie Nov 26 '15 at 21:03
  • @Robbie, In most cases, you do not need these `waterfalls` and `cargos`. But sure, it's awesome library. – vp_arth Nov 26 '15 at 21:10
  • This is awesome man, just implemented it, and it works flawless and fast ;) thx @vp_arth. Getting a nice array back. – jo v Nov 26 '15 at 21:16
  • @vp_arth i guess it depends which you prefer, i find the code much easier to comprehend when using async.js - also `async.auto` is really cool - solves a lot of my async problems - here's an example of it: http://stackoverflow.com/a/32029426/459517 – Robbie Nov 26 '15 at 21:20
  • I just hate I need all of `if (err) return next(err);` rows :) – vp_arth Nov 26 '15 at 21:24
  • sorry, i deleted that :) - you do need to handle the errors, but a lot of the time you can just pass it on and handle it higher up - if you use async.auto, there is no need for it because if your dependency isn't satisfied (i.e. an error happened) then the task never gets executed and you can handle it in the final callback. – Robbie Nov 26 '15 at 21:35