fs模块 为何不能在异步读取文件中使用return?
发布于 6 年前 作者 RocketV2 4090 次浏览 来自 问答

具体代码如下: function getJs(page){ var uri = “./js/”+page+".js"; fs.readFile(uri,function(err,data){ return data; }); } 我的想法是读取完文件后,将数据返回;但是提示错误: 2016-08-26 00:56:40屏幕截图.png 这是为何?

13 回复

这个时候是恶补异步编程的最好的时候,别人给你一语道破,你的思维还是很难扭转。我写过几篇入门文章(Nodejs入门部分),https://github.com/imfly/bitcoin-on-nodejs 其中,我建议使用nodejs要养成异步调用的习惯(几个编码习惯之一),看看是否有帮助

@imfly 好的,非常感谢

这个就是异步跟同步的区别了,习惯就好了,加个callback

@oyosc fs.readFile() 函数中第二个参数不是回调函数吗?

那个只是fs模块自带的而已,一般我们处理业务的时候都是在最开始的函数参数那里加个callback,然后再在你说的那个回调函数里面callback(data),把得到的数据传过去,再在里面进行业务处理就好了

其实回调并不难理解,仔细分析程序执行过程中的参数传递和数据流向。那个return仅仅是结束了最内层的函数,并没有把数据传递出去

如果真的需要类似于写同步代码的方式,可以这样。

import fs from 'fs'

function getJS(uri) {
  return new Promise((resolve, reject) => {
    fs.readFile(uri, (err, data) => {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

// test a little bit
(async () => {
  const uri = './a.js'
  const content = await getJS(uri)
  console.log(content.toString())
})()

@metrue 请问直接把getJS写成async函数怎么样?

@hezhongfeng async 可以声明一个异步函数,此函数需要返回一个 Promise 对象。await 可以等待一个 Promise 对象 resolve,并拿到结果。fs.readFile必须包装成promise吧。

@zp1112 async返回一个promise对象 那么将getJS写成async函数

	var uri = “./js/”+page+".js";
	return await fs.readFile(uri);

这样是否可以

@hezhongfeng 不可以的啊,我试过了,fs.readFile只是个普通的回调函数,必须把fs.readFile分装成promise吧。因为await后面必须跟promise。你可以看看阮一峰的es6,也可以看看这个https://cnodejs.org/topic/5640b80d3a6aa72c5e0030b6

@zp1112 哦 我还以为他是promise呢,普通的话就必须得包一层了 一般我都找promise的使用,那样使用就简单了

如果非要采取通常的顺序编程的逻辑处理异步,可以考虑使用 函数式编程,请看这篇 入门文章 《函数式编程入门》 的异步处理部分

按照文章里的例子,上面的代码,就可以这样处理:

var fs = require('fs');
var _ = require('ramda');  //npm install ramda --save
var Task = require('data.task'); //npm install data.task --save

// read : String -> Task(Error, Buffer)
function read(path) {
    return new Task(function(reject, resolve) {
        fs.readFile(path, 'utf8', function(error, data) {
            if (error) reject(error)
            else resolve(data)
        })
    })
}

// decode : Task(Error, Buffer) -> Task(Error, String)
function decode(buffer) {
    return buffer.map(function(a) {
        return a.toString('utf-8')
    })
}

function url(page){
	return “./js/”+page+".js";
}

var getJs = _.compose(decode, read, url);

调用的时候,这样:

getJs("page1").fork(
    function(error) {
        throw error;
    },

    function(data) {
        console.log(data); //这里获得并处理数据
    }
)

函数式编程本身就是考虑数据流的概念,所以一路只写表达式,非常流畅。不过这里简单的读取文件,看不出它优势来,逻辑更复杂的时候,优势会更明显。

回到顶部