amerej
amerej

Reputation: 139

Create an object of objects

I'm trying to create an object of objects in JS but I think I have some problems with the asynchronous execution.

Here is my code:

// Extract data (episode number, characters firstname's) from .docx to JSON

var mammoth = require("mammoth")

function docx2Object (filepath) {
    
    return mammoth.extractRawText({path: filepath})
    .then(function (res) {
        return res.value;
    })
    .then(function (res) {
        let arr = {}
        arr["number"] = "" + res.match(/(?!Episode #)\d+/)
        arr["names"] = [...new Set(res.match(/^[^:\r\n]+(?=:)/gm))]
        return arr
    })
}

function files2JSON (arrayScripts) {
    
    let arr = {}
    let i = 0
    arrayScripts.forEach(function(element) {
        docx2Object(element).then(function (res) {
            arr[i++] = res
            console.log(JSON.stringify(arr, null, '\t'))
        })
    })
    return JSON.stringify(arr, null, '\t')
}

let arrayScripts = ["doc1.docx", "doc2.docx"]
console.log(files2JSON(arrayScripts))

And here is the output:

{}

{
    "0": {
        "number": "10600",
        "names": [
            "Hilary",
            "Jean-Claude",
            "Devon",
            "Jean Claude",
            "Cane",
            "Lily",
            "Jack",
            "Phyllis",
            "Victor",
            "Nikki",
            "Neil",
            "Paul",
            "Dr. Barrett",
            "Christine",
            "Kelly"
        ]
    }
}
{
    "0": {
        "number": "10600",
        "names": [
            "Hilary",
            "Jean-Claude",
            "Devon",
            "Jean Claude",
            "Cane",
            "Lily",
            "Jack",
            "Phyllis",
            "Victor",
            "Nikki",
            "Neil",
            "Paul",
            "Dr. Barrett",
            "Christine",
            "Kelly"
        ]
    },
    "1": {
        "number": "10601",
        "names": [
            "Hilary",
            "Devon",
            "Jean+Claude",
            "Jean + Claude",
            "Jean/Claude",
            "Jean / Claude",
            "Cane",
            "Lily",
            "Jack",
            "Phyllis",
            "Victor",
            "Nikki",
            "Neil",
            "Paul",
            "Dr. Barrett",
            "Christine",
            "Kelly"
        ]
    }
}

My array is empty and my indexes do not match.Can anyone help?

Upvotes: 0

Views: 80

Answers (2)

Manish Joshi
Manish Joshi

Reputation: 93

This will help to get your output.As you are using global wrong increment count and also mammoth.extractRawText() method containing wrong code.

// Extract data (episode number, characters firstname's) from .docx to JSON
var mammoth = require("mammoth");

function docx2Object (filepath) {

  return mammoth.extractRawText({path: filepath})
      .then(function (res) {
        return res.value;
      }).then(function (res) {
        var arr = {};
        arr["number"] = "" + res.match(/(?!Episode #)\d+/);
        //arr["names"] = [...new Set(res.match(/^[^:\r\n]+(?=:)/gm))];
        return arr
      });

}

function files2JSON (arrayScripts) {
  var arr = {};

  arrayScripts.forEach(function(element,index) {
    docx2Object(element).then(function (res) {
      arr[index++] = res;
      console.log(res,index)
      console.log(JSON.stringify(arr, null, '\t'));
    })
  });
  return JSON.stringify(arr, null, '\t');
}

var arrayScripts = ["doc1.docx", "doc2.docx"];
console.log(files2JSON(arrayScripts));

Upvotes: 0

Steven Goodman
Steven Goodman

Reputation: 576

I think your problem is with

arrayScripts.forEach(function(element) {
    docx2Object(element).then(function (res) {
        arr[i++] = res
        console.log(JSON.stringify(arr, null, '\t'))
    })
})

The docx2Object call is asynchronous meaning iteration of the forEach will return and execute immediately. This means files2JSON might execute before all of the processing is done.

Most likely what you want to do is store each promise into an array and then use Promise.all() to resolve them all at once and return the promise from Promise.all() and wait on it. Overall the structure of this would look something like

function asyncTask1(task) {
  return getPromise(task);
}

function asyncTask2() {
  var tasks = ["eat", "sleep"];
  var promises = tasks.map(function(task) {
    return asyncTask1(task);
  });
  return Promise.all(promises);
}

asyncTask2().then(function(response) {
  console.log("I ate and slept.");
});

Number one thing that I personally do when debugging async code is just throw a whole bunch of console.logs and see what gets executed when. It really helps seeing the order of execution.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Upvotes: 1

Related Questions