首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Node.js中用promises替换回调

在Node.js中用promises替换回调
EN

Stack Overflow用户
提问于 2015-02-10 21:03:52
回答 8查看 95.8K关注 0票数 95

我有一个简单的节点模块,它连接到数据库,并有几个函数来接收数据,例如这个函数:

dbConnection.js:

代码语言:javascript
复制
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);
        }
      });
    });
  }
};

该模块将以这种方式从不同的节点模块调用:

app.js:

代码语言:javascript
复制
import dbCon from './dbConnection.js';

dbCon.getUsers(console.log);

我想使用promises而不是回调来返回数据。到目前为止,我已经阅读了以下线程中的嵌套promises:Writing Clean Code With Nested Promises,但我找不到任何足够简单的解决方案来满足这个用例。使用promise返回result的正确方式是什么?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2015-02-10 21:35:47

使用Promise

我推荐看一下MDN's Promise docs,它为使用Promise提供了一个很好的起点。或者,我确信有许多在线教程可用。:)

注意:现代浏览器已经支持MDN6的Promise规范(请参阅上面链接的ECMAScript文档),我假设您想要使用本机实现,而不是第三方库。

至于实际的例子..。

基本原理是这样工作的:

  1. 您的API名为
  2. 您创建了一个新的Promise对象,此对象接受单个函数作为构造函数参数
  3. 您提供的函数由底层实现调用,该函数被赋予两个函数- resolveresolve。执行逻辑时,您可以调用其中一个函数来满足Promise或拒绝它,并返回错误

这可能看起来很多,所以这里有一个实际的示例。

代码语言:javascript
复制
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/await support进行了升级。您现在可以将函数声明为async,这意味着它们会自动返回一个Promise,该can在异步函数完成执行时会被解析。在此函数中,可以使用await关键字等待另一个Promise解析。

下面是一个示例:

代码语言:javascript
复制
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
}
票数 105
EN

Stack Overflow用户

发布于 2015-02-10 21:17:36

使用,您可以使用Promise.promisifyAll (和Promise.promisify)将Promise ready方法添加到任何对象。

代码语言:javascript
复制
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')
        });
};

并像这样使用:

代码语言:javascript
复制
getUsersAsync().then(console.log);

代码语言:javascript
复制
// Spread because MySQL queries actually return two resulting arguments, 
// which Bluebird resolves as an array.
getUsersAsync().spread(function(rows, fields) {
    // Do whatever you want with either rows or fields.
});

添加处理器

蓝鸟支持很多功能,其中之一是处理器,它允许你在Promise.usingPromise.prototype.disposer的帮助下安全地处理连接结束后的连接。下面是我的应用程序中的一个示例:

代码语言:javascript
复制
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();
        });
}

然后像这样使用它:

代码语言:javascript
复制
exports.getUsersAsync = function () {
    return Promise.using(getConnection()).then(function (connection) {
            return connection.queryAsync('SELECT * FROM Users')
        });
};

一旦promise用值解析(或用Error拒绝),这将自动结束连接。

票数 31
EN

Stack Overflow用户

发布于 2017-11-15 07:35:50

Node.js版本8.0.0+:

您不再需要使用bluebird来简化node API方法。因为,在8+版本中,您可以使用本机util.promisify

代码语言:javascript
复制
const util = require('util');

const connectAsync = util.promisify(connection.connectAsync);
const queryAsync = util.promisify(connection.queryAsync);

exports.getUsersAsync = function () {
    return connectAsync()
        .then(function () {
            return queryAsync('SELECT * FROM Users')
        });
};

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

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28432401

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档