Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/425.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在Node.js中将回调替换为承诺_Javascript_Node.js_Promise - Fatal编程技术网

Javascript 在Node.js中将回调替换为承诺

Javascript 在Node.js中将回调替换为承诺,javascript,node.js,promise,Javascript,Node.js,Promise,我有一个简单的节点模块,它连接到数据库,并具有多个接收数据的功能,例如此功能: dbConnection.js: import mysql from 'mysql'; const connection = mysql.createConnection({ host: 'localhost', user: 'user', password: 'password', database: 'db' }); export default { getUsers(callback)

我有一个简单的节点模块,它连接到数据库,并具有多个接收数据的功能,例如此功能:


dbConnection.js:

import mysql from 'mysql';

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'user',
  password: 'password',
  database: 'db'
});

export default {
  getUsers(callback) {
    connection.connect(() => {
      connection.query('SELECT * FROM Users', (err, result) => {
        if (!err){
          callback(result);
        }
      });
    });
  }
};
import dbCon from './dbConnection.js';

dbCon.getUsers(console.log);
该模块将通过这种方式从不同的节点模块调用:


app.js:

import mysql from 'mysql';

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'user',
  password: 'password',
  database: 'db'
});

export default {
  getUsers(callback) {
    connection.connect(() => {
      connection.query('SELECT * FROM Users', (err, result) => {
        if (!err){
          callback(result);
        }
      });
    });
  }
};
import dbCon from './dbConnection.js';

dbCon.getUsers(console.log);
我希望使用承诺而不是回调来返回数据。 到目前为止,我已经在下面的线程中读到了关于嵌套承诺的内容:,但是我找不到任何对于这个用例来说足够简单的解决方案。
使用承诺返回
结果的正确方法是什么?

设置承诺时,使用两个参数,
resolve
reject
。在成功的情况下,调用
resolve
并显示结果;在失败的情况下,调用
reject
并显示错误

然后你可以写:

getUsers().then(callback)

回调
将使用从
getUsers
返回的承诺的结果进行调用,即
结果

假设您的数据库适配器API本身不输出
承诺
您可以执行以下操作:

exports.getUsers = function () {
    var promise;
    promise = new Promise();
    connection.connect(function () {
        connection.query('SELECT * FROM Users', function (err, result) {
            if(!err){
                promise.resolve(result);
            } else {
                promise.reject(err);
            }
        });
    });
    return promise.promise();
};
如果数据库API确实支持
承诺
,您可以执行以下操作:(这里您看到了承诺的威力,您的回调绒毛几乎消失了)

使用
.then()
返回新的(嵌套的)承诺

致电:

module.getUsers().done(function (result) { /* your code here */ });


我使用了一个模拟API来实现我的承诺,您的API可能会有所不同。如果您向我展示您的API,我可以定制它。

使用Q库,例如:

function getUsers(param){
    var d = Q.defer();

    connection.connect(function () {
    connection.query('SELECT * FROM Users', function (err, result) {
        if(!err){
            d.resolve(result);
        }
    });
    });
    return d.promise;   
}
使用可以使用(和)向任何对象添加承诺就绪的方法

var Promise = require('bluebird');
// Somewhere around here, the following line is called
Promise.promisifyAll(connection);

exports.getUsersAsync = function () {
    return connection.connectAsync()
        .then(function () {
            return connection.queryAsync('SELECT * FROM Users')
        });
};
然后像这样使用:

getUsersAsync().then(console.log);

添加处理器 Bluebird支持很多功能,其中一个是disposer,它允许您在连接结束后通过
Promise.using
Promise.prototype.disposer
安全地处理连接。以下是我的应用程序中的一个示例:

function getConnection(host, user, password, port) {
    // connection was already promisified at this point

    // The object literal syntax is ES6, it's the equivalent of
    // {host: host, user: user, ... }
    var connection = mysql.createConnection({host, user, password, port});
    return connection.connectAsync()
        // connect callback doesn't have arguments. return connection.
        .return(connection) 
        .disposer(function(connection, promise) { 
            //Disposer is used when Promise.using is finished.
            connection.end();
        });
}
函数getConnection(主机、用户、密码、端口){
//在这一点上,连接已经得到保证
//对象文字语法是ES6,它相当于
//{主机:主机,用户:用户,…}
var connection=mysql.createConnection({host,user,password,port});
返回连接
//连接回调没有参数。返回连接。
.返回(连接)
.disposer(功能(连接、承诺){
//处置器在使用完成后使用。
连接。结束();
});
}
然后像这样使用它:

getUsersAsync().then(console.log);
exports.getUsersAsync=函数(){
返回承诺。使用(getConnection())。然后(函数(连接){
return connection.querySync('SELECT*FROM Users')
});
};

一旦promise与值解析(或因
错误而拒绝),这将自动结束连接。

使用
promise
类 我建议看一看哪一个提供了使用承诺的良好起点。或者,我相信网上有很多教程。:)

注意:现代浏览器已经支持ECMAScript 6承诺规范(参见上面链接的MDN文档),我假设您希望使用本机实现,而不使用第三方库

作为一个实际的例子

基本原理如下:

getUsersAsync().then(console.log);
  • 您的API被调用
  • 创建一个新的Promise对象,该对象将单个函数作为构造函数参数
  • 您提供的函数由底层实现调用,该函数有两个函数-
    resolve
    reject
  • 一旦你做了你的逻辑,你调用其中的一个来完成承诺或者用一个错误来拒绝它
  • 这看起来可能很多,所以这里是一个实际的例子

    exports.getUsers = function getUsers () {
      // Return the Promise right away, unless you really need to
      // do something before you create a new Promise, but usually
      // this can go into the function below
      return new Promise((resolve, reject) => {
        // reject and resolve are functions provided by the Promise
        // implementation. Call only one of them.
    
        // Do your logic here - you can do WTF you want.:)
        connection.query('SELECT * FROM Users', (err, result) => {
          // PS. Fail fast! Handle errors first, then move to the
          // important stuff (that's a good practice at least)
          if (err) {
            // Reject the Promise with an error
            return reject(err)
          }
    
          // Resolve (or fulfill) the promise with data
          return resolve(result)
        })
      })
    }
    
    // Usage:
    exports.getUsers()  // Returns a Promise!
      .then(users => {
        // Do stuff with users
      })
      .catch(err => {
        // handle errors
      })
    
    使用异步/等待语言功能(Node.js>=7.6) 在Node.js 7.6中,v8 JavaScript编译器升级为。现在可以将函数声明为
    async
    ,这意味着它们会自动返回一个
    承诺
    ,该承诺在异步函数完成执行时解析。在该函数中,您可以使用
    wait
    关键字等待,直到另一个承诺得到解决

    以下是一个例子:

    exports.getUsers = async function getUsers() {
      // We are in an async function - this will return Promise
      // no matter what.
    
      // We can interact with other functions which return a
      // Promise very easily:
      const result = await connection.query('select * from users')
    
      // Interacting with callback-based APIs is a bit more
      // complicated but still very easy:
      const result2 = await new Promise((resolve, reject) => {
        connection.query('select * from users', (err, res) => {
          return void err ? reject(err) : resolve(res)
        })
      })
      // Returning a value will cause the promise to be resolved
      // with that value
      return result
    }
    

    Node.js版本8.0.0+:

    import mysql from 'mysql';
    
    const connection = mysql.createConnection({
      host: 'localhost',
      user: 'user',
      password: 'password',
      database: 'db'
    });
    
    export default {
      getUsers(callback) {
        connection.connect(() => {
          connection.query('SELECT * FROM Users', (err, result) => {
            if (!err){
              callback(result);
            }
          });
        });
      }
    };
    
    import dbCon from './dbConnection.js';
    
    dbCon.getUsers(console.log);
    
    您不再需要使用promisify节点API方法。因为,从版本8+开始,您可以使用本机:


    现在,不必使用任何第三方库来执行promisify

    下面的代码仅适用于节点-v>8.x

    我用这个

    阅读这篇文章

    database.js

    var mysql = require('mysql'); 
    
    // node -v must > 8.x 
    var util = require('util');
    
    
    //  !!!!! for node version < 8.x only  !!!!!
    // npm install util.promisify
    //require('util.promisify').shim();
    // -v < 8.x  has problem with async await so upgrade -v to v9.6.1 for this to work. 
    
    
    
    // connection pool https://github.com/mysqljs/mysql   [1]
    var pool = mysql.createPool({
      connectionLimit : process.env.mysql_connection_pool_Limit, // default:10
      host     : process.env.mysql_host,
      user     : process.env.mysql_user,
      password : process.env.mysql_password,
      database : process.env.mysql_database
    })
    
    
    // Ping database to check for common exception errors.
    pool.getConnection((err, connection) => {
    if (err) {
        if (err.code === 'PROTOCOL_CONNECTION_LOST') {
            console.error('Database connection was closed.')
        }
        if (err.code === 'ER_CON_COUNT_ERROR') {
            console.error('Database has too many connections.')
        }
        if (err.code === 'ECONNREFUSED') {
            console.error('Database connection was refused.')
        }
    }
    
    if (connection) connection.release()
    
     return
     })
    
    // Promisify for Node.js async/await.
     pool.query = util.promisify(pool.query)
    
    
    
     module.exports = pool
    
    2019: 使用本机模块
    const{promisify}=require('util')
    将旧的回调模式转换为promise模式,这样您就可以从
    async/await
    code中获得benfit

    const {promisify} = require('util');
    const glob = promisify(require('glob'));
    
    app.get('/', async function (req, res) {
        const files = await glob('src/**/*-spec.js');
        res.render('mocha-template-test', {files});
    });
    
    

    请看,如果您正在使用kriskowal的Q库。@leo.249:您是否阅读了Q文档?您是否已经尝试将其应用于您的代码-如果是,请发布您的尝试(即使不起作用)?你到底被困在哪里?您似乎已经找到了一个非简单的解决方案,请发布。@leo.249 Q几乎没有维护-上次提交是3个月前。Q开发人员只对v2分支感兴趣,而且这还不足以为生产做好准备。从10月份开始,问题跟踪程序中有未解决的问题,但没有评论。我强烈建议您考虑一个维护良好的承诺库。超级相关的允诺库有一个<代码>承诺>代码>构造函数和一个<代码>约定()/>代码>方法。谢谢。我只是在练习一些node.js,我发布的内容就是其中的全部内容,这是一个非常简单的示例,可以帮助您了解如何使用承诺。您的解决方案看起来不错,但要使用
    promise=newpromise(),我需要安装什么npm包?虽然您的API现在返回承诺,但您还没有摆脱厄运金字塔