javascript - 如何通过嵌套正确链接 Promises

标签 javascript node.js promise

我的 Node 项目目前包含一个嵌套回调的横向圣诞树,以便获取数据并以正确的顺序处理它们。现在我正在尝试使用 Promises 重构它,但我不确定如何正确地进行重构。

假设我正在获取一个办公室列表,然后是每个办公室的所有员工,然后是每个员工的薪水。最后,所有实体(办公室、员工和薪水)都应该链接在一起并存储在数据库中。

一些伪代码说明了我当前的代码(省略了错误处理):

fetch(officesEndpoint, function (data, response) {
    parse(data, function (err, offices) {
        offices.forEach(function (office) {
            save(office);
            fetch(employeesEndPoint, function (data, response) {
                parse(data, function (err, employees) {
                    // link each employee to office
                    save(office);
                    save(employee);
                    employees.forEach(function () {
                        fetch(salaryEndpoint, function (data, response) {
                            parse(data, function (err, salaries) {
                                // link salary to employee
                                save(employee);
                            });
                        });
                    });
                });
            });
        });
    });
});

我尝试用 promises 解决这个问题,但我有几个问题:

  • 有点冗长?
  • 每个办公室都需要链接到各自的员工,但在 saveEmployees 函数中,我只能访问员工,而不是链中更上层的办公室:

var restClient = require('node-rest-client');
var client = new restClient.Client();
var xml2js = require('xml2js');

// some imaginary endpoints
var officesEndpoint = 'http://api/offices';
var employeesEndpoint = 'http://api/offices/employees';
var salaryEndpoint = 'http://api/employees/:id/salary';


function fetch (url) {
    return new Promise(function (resolve, reject) {
        client.get(url, function (data, response) {
            if (response.statusCode !== 200) {
                reject(statusCode);
            }
            resolve(data);
        });
    });
}

function parse (data) {
    return new Promise(function (resolve, reject) {
        xml2js.parseString(data, function (err, result) {
            if (err) {
                reject(err);
            }
            resolve(result);
        });
    });
}

function saveOffices (offices) {
    var saveOffice = function (office) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () {  // simulating async save()
                console.log('saved office in mongodb');
                resolve(office);
            }, 500);
        })
    }
    return Promise.all(offices.map(saveOffice));
}

function saveEmployees (employees) {
    var saveEmployee = function (employee) {
        return new Promise(function (resolve, reject) {
            setTimeout(function () { // simulating async save()
                console.log('saved employee in mongodb');
                resolve(office);
            }, 500);
        })
    }
    return Promise.all(offices.map(saveEmployee));
}

fetch(officesEndpoint)
.then(parse)
.then(saveOffices)
.then(function (savedOffices) {
    console.log('all offices saved!', savedOffices);
    return savedOffices;
})
.then(function (savedOffices) {
    fetch(employeesEndPoint)
    .then(parse)
    .then(saveEmployees)
    .then(function (savedEmployees) {
        // repeat the chain for fetching salaries?
    })
})
.catch(function (error) {
    console.log('something went wrong:', error);
});

最佳答案

你不必嵌套,这也行:

fetch(officesEndpoint)
  .then(parse)
  .then(saveOffices)
  .then(function(savedOffices) {
    console.log('all offices saved!', savedOffices);
    return savedOffices;
  })
  .then(function(savedOffices) {
    // return a promise
    return fetch(employeesEndPoint); // the returned promise can be more complex, like a Promise.all of fetchEmployeesOfThisOffice(officeId)
  })
  // so you can chain at this level
  .then(parse)
  .then(saveEmployees)
  .then(function(savedEmployees) {
    return fetch(salariesEndPoint);
  })
  .catch(function(error) {
    console.log('something went wrong:', error);
  });

关于javascript - 如何通过嵌套正确链接 Promises,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36449621/

相关文章:

javascript - nodejs : async.系列未按顺序执行函数

javascript - 从 promise 创建高地溪流时如何处理 promise 拒绝?

javascript - RxJS zip 和管道组合不起作用

javascript - 在后面的链链接中使用第一个 promise 的值(value)

javascript - Onsen UI 2.0 如何改变 Material 颜色?

javascript - 如何从nodejs模块中删除全局上下文?

regex - 文件名中包含空格的上传导致我的服务器出现错误

Node.js 回调帮助

javascript - 无法在 Sequelize 中使用类模型在数据库中创建表

javascript - 从零重复的数组中随机生成名称?