【问题标题】:Why am I getting a Segmentation fault in Node.js?为什么我在 Node.js 中遇到分段错误?
【发布时间】:2016-10-18 21:17:26
【问题描述】:

我这里有这个功能:

function createInsta(email, userid) {
  if (!fs.existsSync('users/' + email + '/' + userid)) {
    fs.mkdir('users/' + email + '/' + userid)
    fs.writeFileSync(('users/' + email + '/' + userid +  '/instagram.json'), fs.readFileSync("data/data.json", "utf-8"))
    console.log("insta folder created");
  }
  console.log("Initializing Data")
  var data = fs.readFileSync('users/' + email + '/' + userid +  '/instagram.json', "utf-8")
  data = JSON.parse(data);
  var result;
  request(("https://instagram.com/" + userid + "/?__a=1"), function(error, response, body) {
    var res = JSON.parse(body);
    result = res.user.followed_by.count
    if (error) {
      console.log(err)
    }
  })
  while (result === undefined) {
    deasync.sleep(100)
  }
  data.STARTING_COUNTS[0].DAY = result;
  data.STARTING_COUNTS[0].WEEK = result;
  data.STARTING_COUNTS[0].MONTH = result;

}

在控制台打印出Initializing Data 之后,控制台立即显示Segmentation fault

我不知道为什么会这样,我的代码似乎没有任何东西会导致这样的错误。

任何指针?谢谢

【问题讨论】:

  • “任何指针” - 双关语?
  • 我不喜欢 -> while (result === undefined) {deasync.sleep(100) } 的样子,为什么需要它?
  • @Keith 我用它作为这个函数的 nodejs 异步模型的简单快速破解,我在其他函数中使用它没有问题,我怀疑它是段错误的原因跨度>
  • @joews 不是我第一次发这个的时候,但那很有趣哈哈
  • 我会说它最有可能是段错误的候选者。 github.com/abbr/deasync/issues/48 理论上,使用纯形式的 node.js 应该不可能出现段错误,因为 javascript 在沙箱中,但是你的 deasync 是一个 c++ hack,肯定会出现段错误。 Node.Js 从一开始就被设计为异步的,试图强制进入同步模式只是自找麻烦,..

标签: javascript node.js segmentation-fault


【解决方案1】:

正如所承诺的(请原谅双关语),这里开始将您的代码转换为 Promise / await。

这是让您的代码使用 Promise 的开始,需要更多的错误检查等,但我现在故意对代码做的很少,也显示更改,我们可以在继续进行重构.

例如。所有 fs.existsSync 等,都希望成为承诺,所以我们可以摆脱所有同步的东西。您的 node.js 应用会因此而爱上您。

以后,我们可以做得更多。 Promise 内置在浏览器/节点中很好,但我也发现 Promise 库可以让事情变得更容易,我建议 bluebird -> http://bluebirdjs.com/docs/getting-started.html 那里也值得一读,bluebird 有一些有用的实用功能,比如 promisify将使您的 fs.func 更容易。

所以我认为现在应该这样做,我们稍后会进行另一个重构。

//lets mark this function as async..
async function createInsta(email, userid) {
  return new Promise(function (resolve, reject) {
    if (!fs.existsSync('users/' + email + '/' + userid)) {
      fs.mkdir('users/' + email + '/' + userid)
      fs.writeFileSync(('users/' + email + '/' + userid +  '/instagram.json'), fs.readFileSync("data/data.json", "utf-8"))
      console.log("insta folder created");
    }
    console.log("Initializing Data")
    var data = fs.readFileSync('users/' + email + '/' + userid +  '/instagram.json', "utf-8")
    data = JSON.parse(data);    
    request(("https://instagram.com/" + userid + "/?__a=1"), function(error, response, body) {
      if (error) {
        console.log(err)
        return reject(error);
      }
      var res = JSON.parse(body);
      var result = res.user.followed_by.count
      data.STARTING_COUNTS[0].DAY = result;
      data.STARTING_COUNTS[0].WEEK = result;
      data.STARTING_COUNTS[0].MONTH = result;
      resolve(data); //i'm assuming data is what your wanting to return
    })
  });
}

//to be able to use await our function also needs to be async
async function run() {
 var data = await createInsta('bob@bob.com');
}

【讨论】:

  • 谢谢!实际上,在阅读本文之前,我确实研究了 bluebird,并将我的回调代码重构为 Promise:gist.github.com/Vikaton/18cf0891e8c00ff2d7cbfdbfdca83e26 但是您的代码看起来更简洁,您的代码比 Promisified 的代码更好吗?
  • Promisified,只是 Bluebird 用来将 Node 回调转换为基于 Promise 的函数的术语。我添加了一个新帖子,展示了这一点。
  • 你在哪里fs.mkdir,应该是fs.mkdirSync,或者应该传递一个回调。
  • @jonschlinkert 很好,是的。我刚刚在这里复制了 OP 的代码,我只是在重构,我在下面做的第二篇文章做得更好。不知道为什么我没有承诺存在。
【解决方案2】:

好的,让我们重构上一篇文章。

我们使用new Promise() 构造函数只有一个原因,那就是请求是异步的。事实上,我确实犯了一个小错误,因为有些错误不会以正确的方式处理。我应该做的是将new Promise() 移到请求之前。

现在关于 Promises 的一大优点是错误会沿着链传播,在我们的示例中,到目前为止,我们的请求对象中有一个 console.log()。好的是所有未处理的错误都在一个地方处理。在这个例子中,run() 函数似乎是一个不错的地方。

如果您现在查看您的 createInsta 函数,您会认为它正在使用所有同步函数,但实际上除了 existsSync 之外,其他一切都是异步的。就像在 cmets 中提到的那样,existSync 确实想要删除。相反,只需创建目录并在 try catch 中捕获错误,或者更好地创建一个名为 tryMkDir 的实用程序函数,这样做(当然基于承诺).. :)

最后一点,await / async 是一个相当新的 javascript,我认为它是 ES7,我不相信它甚至还没有最终确定。但是你现在可以使用它,通过使用 Babel 之类的东西。

//lets make a Promise based request.
//There is an NPM module that would do this and more
//but this is a good example of making existing callback
//functions into a Promise.

async function promRequest(url) {
  return new Promise(function(resolve, reject) {
    request(url, function(error, response, body) {
      if (error) return reject(error);
      //promises can only return one thing
      //so use an object literal to return more
      resolve({
        response:response,
        body: body
      });
    });
  });
}

//lets also promisify some Node stuff.
var Promise = require('bluebird');

//there is a promisifyall, but I like to be
//specific about what I promisify.
var fsWriteFile = Promise.promisify(fs.writeFile),
    fsReadFile = Promise.promisify(fs.readFile),
    fsMkdir = Promise.promisify(fs.mkdir);


//because promRequest is already a promise
//we can now get rid of the new Promise contructor here.
//The only part of this function that is now async
//is existsSync, the exists() in node is depreciated
//due to potential race conditions, really this 
//should be altered to just try and create dirctory
//and catch error if exists.
async function createInsta(email, userid) {
  if (!fs.existsSync('users/' + email + '/' + userid)) {
    await fsMkdir('users/' + email + '/' + userid);
    await fsWriteFile(('users/' + email + '/' + userid +  '/instagram.json'), await fsReadFile("data/data.json", "utf-8"));
    console.log("insta folder created");
  }
  console.log("Initializing Data")
  var data = await fsReadFile('users/' + email + '/' + userid +  '/instagram.json', "utf-8")
  data = JSON.parse(data);    
  var res = JSON.parse(
    await promRequest("https://instagram.com/" + userid + "/?__a=1").body);
  var result = res.user.followed_by.count
  data.STARTING_COUNTS[0].DAY = result;
  data.STARTING_COUNTS[0].WEEK = result;
  data.STARTING_COUNTS[0].MONTH = result;
  return data;
}

//to be able to use await our function also needs to be async
async function run() {
  //lets catch all unahandled errors here.
  try {
    var data = await createInsta('bob@bob.com');
  } catch (e) {
    //fantasic any error's can now be logged
    //eg. fsMkdir might have failed and it's still
    //going to be logged here..
    console.log(e);
  }
}

【讨论】:

  • 非常感谢!
猜你喜欢
  • 2020-08-03
  • 2013-01-23
  • 2020-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多