使用本机ES6 Promises去标准化/压缩标准回调

时间:2017-05-30 10:54:59

标签: javascript node.js ecmascript-6 promise es6-promise

Q库(https://github.com/kriskowal/q)为遵循Node标准回调布局的函数提供了非常有用的适配器,即最后一个参数是function(err, result)

return Q.nfcall(FS.readFile, "foo.txt", "utf-8");
return Q.nfapply(FS.readFile, ["foo.txt", "utf-8"]);

在"适应节点"中进一步讨论了这个问题。自述文件的一部分。

当使用原生的ES6 Promises来实现同样的目标时,人们常常会遇到这种笨拙的火车残骸:

const fs = require('fs');
const http = require('http');

const server = http.createServer((req, res) => {
    new Promise((resolve, reject) => { 
        fs.readFile('/etc/motd', (err, data) => {
            if(err) { 
                reject(err.toString());
                return;
            }

            resolve(data);
        });
    }).then(data => {
        res.writeHead(200);
        res.end(data);
    }).catch(e => {
        res.writeHead(500);
        res.end(e);
    });
}).listen(8000);

虽然这确实可以平息最坏情况下的回调地狱,但它仍然在视觉上混乱而难以理解。

显然,可以将其分解为函数并内联较少的代码以使其更具可读性,但该解决方案可以很好地纠正承诺应该首先帮助解决的回调问题。 :-)

对于标准的ES2015 / 6 Promise功能集,我有什么遗漏可以让人们在这里节省一些麻烦吗?如果做不到这一点,我们将不胜感激地建议低热量的polyfill。

3 个答案:

答案 0 :(得分:3)

浏览器和Node.js 7及以下

最受欢迎的基于回调的软件包具有与之相关的对应软件包,例如: fs的{​​{3}}和fs-extra

mz/fs是广为人知的默认解决方案,默认情况下使用原生Promisepify也可以提供帮助,例如Other promise-related packages from this maintainer来宣传一次性事件监听器。

http示例涉及多次触发的回调,这是基于承诺的函数无法替换的。但显然可以像fs那样事先宣传基于回调的内容(如p-event所示):

const pify = require('pify');
const fs = pify(require('fs'), {
  exclude: [/^exists/, /.+(Stream|Sync)$/, /watch/],
  excludeMain: true
});
...
http.createServer((req, res) => {
    let code;
    let body;

    fs.readFile('/etc/motd')
    .then(
      data => {
        body = data;
        code = 200;
      },
      err => {
        body = String(err);
        code = 500;
      }
    )
    .then(() => {
      res.writeHead(code);
      res.end(body);
    });
})

如果没有第三方宣传解决方案,开发人员将被迫重新发明轮子,这涉及使用new Promise构建承诺,如原始示例所示。

值得注意的是,Bluebird是ES6承诺的流行替代品,特别是因为它提供了开箱即用的所需功能,包括pify-fs package

Node.js 8

从8.0.0开始,Node内置了promisification来宣传节点式回调。像fs这样的普通对象的批处理默认配方是

const util = require('util');
const fs = Object.assign({}, require('fs'),
    Object.entries(require('fs'))
    .filter(([, val]) => typeof val === 'function')
    .filter(([key]) => !/^[A-Z_]|^exists|.+(Stream|Sync)$|watch/.test(key))
    .reduce((fs, [key, val]) => Object.assign(fs, { [key]: util.promisify(val) }), {})
);

答案 1 :(得分:0)

我想一个人总能创造出自己的......

fun main(args: Array<String>) {
    print("Enter your Number")
    var number:Int = readLine()!!.toInt()
    if (number>5) {
        println(number + "is more than 5")
    } else if (number==5) {
        println(number + "is equal than 5")

    } else {
        println(number + "is less than 5")
    }

    println("Thank You")
    }

答案 2 :(得分:0)

您可以完全避免承诺,只需通过nsynjs同步执行您的代码即可。您的代码将转换如下:

步骤1.将带有回调的慢速函数包装到nsynjs-aware包装器中:

// wrappers.js

var fs=require('fs');
exports.readFile = function (ctx,name) {
    console.log("reading config");
    var res={};
    fs.readFile( name, "utf8", function( error , data){
        if( error ) res.error = error;
        res.data = data;
        ctx.resume(error);
    } );
    return res;
};
exports.readFile.nsynjsHasCallback = true;

步骤2:将您的逻辑编写为同步,并将其置于函数中:

const synchronousCode = function(req,res,wrappers) {
    try {
        var data = wrappers.readFile(nsynjsCtx,'/etc/motd').data;
        res.writeHead(200);
        res.end(data);
    }
    catch(e) {
        res.writeHead(500);
        res.end(e);
    };
}

步骤3.通过nsynjs执行该功能:

// index.js
const fs = require('fs');
const http = require('http');
const nsynjs = require('nsynjs');
const wrappers = require('./wrappers');

const synchronousCode = function(req,res,wrappers) {
    ...
};

const server = http.createServer(function(req, res){
    nsynjs.run(synchronousCode,{},req,res,wrappers,function(){
        console.log('synchronousCode is done');
    })
}).listen(8000);

请在此处查看类似示例https://github.com/amaksr/nsynjs/tree/master/examples/node-module-loading