Javascript 在这种情况下,如何避免回调地狱?

Javascript 在这种情况下,如何避免回调地狱?,javascript,node.js,asynchronous,callback,Javascript,Node.js,Asynchronous,Callback,正如您所看到的,我有以下代码,函数中的每个函数都依赖于封闭函数的返回值。但问题是,当我继续使用此方法编码时,就会出现回调地狱。如何避免这个地狱 User.getUserDetail(req.user.id, function(userDetail) { if(req.user.entity_id != '-1') { Entity.getEntityPrimary(req.user.entity_id, function(entityPrimary) {

正如您所看到的,我有以下代码,函数中的每个函数都依赖于封闭函数的返回值。但问题是,当我继续使用此方法编码时,就会出现回调地狱。如何避免这个地狱

User.getUserDetail(req.user.id, function(userDetail) {
       if(req.user.entity_id != '-1') {
           Entity.getEntityPrimary(req.user.entity_id, function(entityPrimary) {
               Entity.getEntityPayment(req.user.entity_id, function(entityPayment) {
                   if(entityPayment.length > 0) {
                       Entity.subscriptionInfo(entityPayment[0]['date'], entityPayment[0]['exp_date'], function(isSubscribed) {
                           res.render('capitol', {
                               user: req.user,
                               title: 'MCIC',
                               user_detail: userDetail,
                               entity_primary: entityPrimary,
                               entity_payment: entityPayment,
                               subscriber: true,
                               is_subscribed: isSubscribed
                           })
                       })
                   } else {
                       res.render('capitol', {
                           user: req.user,
                           title: 'MCIC',
                           user_detail: userDetail,
                           entity_primary: entityPrimary,
                           entity_payment: entityPayment,
                           subscriber: false
                       })
                   }
               })
           })
       } else {
           res.render('capitol', {
               user: req.user,
               title: 'MCIC',
               user_detail: userDetail
           })
       }
   })
模型文件如下所示

const MySql = require('../comms/mysql')
const User = module.exports = {}

User.getUserByUsername = function(username, callback) {
    MySql.connection.query('SELECT id, username, password, is_active, email, mobile, user_type_id, entity_id FROM `user` WHERE `username` = ?', username, function(err, rows, fields) {
        callback(rows)
    })
}

User.getUserById = function(id, callback) {
    MySql.connection.query('SELECT id, username, password, is_active, email, mobile, user_type_id, entity_id FROM `user` WHERE `id` = ?', id, function(err, rows, fields) {
        callback(err, rows)
    })
}

User.getUserDetail = function(id, callback) {
    MySql.connection.query('SELECT first_name, last_name, dob, address_no, address_street, address_district, address_postal_code, profile_picture, user_id FROM `user_detail` WHERE `user_id` = ?', id, function(err, rows, fields) {
        callback(rows)
    })
}

我在一个制作网站上使用这段代码。如何轻松地从回调地狱过渡到结构良好的代码?

使用JavaScript承诺

step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4
            });
        });
    });
});
可以制作

Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
    // Do something with value4
})
.catch(function (error) {
    // Handle any error from all above steps
})

阅读此处的更多内容

要获得一些快速奖励,您可以将回调函数提取为位于模块级别的命名函数:

// Before: Deeply nested

asyncOperationA(function(resA) {
  asyncOperationB(resA, function(resB) {
    asyncOperationC(resB, function(resC) {
      console.log(resC)
    })
  })
})


// After: flattened

function handleA(resA) {
  asyncOperationB(handleB)
}

function handleB(resB) {
  asyncOperationC(handleC)
}

function handleC(resC) {
  console.log(resC)
}

asyncOperationA(handleA)
更好的选择是修改代码以使用承诺。使用async/await关键字可以获得最大的可读性。要使用async/await,您需要使用最新的节点版本,或者使用一个transpiler将其转换为普通JavaScript。

使用:

我使用这种模式。我使用的是Babel,但是还有其他选项可以获得async Wait支持。我碰巧正在使用PostgreSQL,我的同步查询如下所示:

const results = await db.tx(t => t.batch([query1, query2]));

您可以像这样使用
async/await
删除回调地狱

const Promise = require('bluebird');
const User = Promise.promisifyAll(require('PATH_TO_USER'));
const Entity = Promise.promisifyAll(require('PATH_TO_ENTITY'));

async function yourController(req, res, next) {
  try {
    const userDetail = await User.getUserDetail(req.user.id);
    if(req.user.entity_id !== -1) {
      const entityPrimary = await Entity.getEntityPrimary(req.user.entity_id);
      const entityPayment = await Entity.getEntityPayment(req.user.entity_id);

      if(entityPayment.length > 0) {
        const isSubscribed = await Entity.subscriptionInfo(entityPayment[0]['date'], entityPayment[0]['exp_date']);
        return res.render('capitol', {
          user: req.user,
          title: 'MCIC',
          user_detail: userDetail,
          entity_primary: entityPrimary,
          entity_payment: entityPayment,
          subscriber: true,
          is_subscribed: isSubscribed
        })
      } else {
          return res.render('capitol', {
            user: req.user,
            title: 'MCIC',
            user_detail: userDetail,
            entity_primary: entityPrimary,
            entity_payment: entityPayment,
            subscriber: false
          })
      }
    } else {
        return res.render('capitol', {
          user: req.user,
          title: 'MCIC',
          user_detail: userDetail
        })
    }
  } catch(e) {
    // handle exception here
  }
}
步骤是

  • 向控制器添加
    async
    关键字,例如
    async函数yourController(req、res、next)
  • 使用
    bluebird
  • 使用
    wait

Promisify回调和异步/等待承诺然后,您将得到线性代码。函数。更多功能。这很好。另外请注意,这里不需要使用
Q
库,普通的javascript
Promise
就足够了。
const Promise = require('bluebird');
const User = Promise.promisifyAll(require('PATH_TO_USER'));
const Entity = Promise.promisifyAll(require('PATH_TO_ENTITY'));

async function yourController(req, res, next) {
  try {
    const userDetail = await User.getUserDetail(req.user.id);
    if(req.user.entity_id !== -1) {
      const entityPrimary = await Entity.getEntityPrimary(req.user.entity_id);
      const entityPayment = await Entity.getEntityPayment(req.user.entity_id);

      if(entityPayment.length > 0) {
        const isSubscribed = await Entity.subscriptionInfo(entityPayment[0]['date'], entityPayment[0]['exp_date']);
        return res.render('capitol', {
          user: req.user,
          title: 'MCIC',
          user_detail: userDetail,
          entity_primary: entityPrimary,
          entity_payment: entityPayment,
          subscriber: true,
          is_subscribed: isSubscribed
        })
      } else {
          return res.render('capitol', {
            user: req.user,
            title: 'MCIC',
            user_detail: userDetail,
            entity_primary: entityPrimary,
            entity_payment: entityPayment,
            subscriber: false
          })
      }
    } else {
        return res.render('capitol', {
          user: req.user,
          title: 'MCIC',
          user_detail: userDetail
        })
    }
  } catch(e) {
    // handle exception here
  }
}