如何正确链接Promise与嵌套

6 javascript node.js promise

我的节点项目当前包含一个嵌套的回调圣诞树,以便获取数据并按正确的顺序处理它们.现在我正在尝试使用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);
                            });
                        });
                    });
                });
            });
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

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

  • 那种冗长?
  • 每个办公室都需要与他们各自的员工联系,但在这个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);
});
Run Code Online (Sandbox Code Playgroud)

Ber*_*rgi 0

您承诺的功能fetchparse和 都很好。有了这些,您可以重构当前的代码以在适用的情况下使用承诺、链式而不是嵌套式,并省略一堆错误处理样板:saveOfficessaveEmployees

fetch(officesEndpoint)
.then(parse)
.then(function(offices) {
    return Promise.all(offices.map(function(office) {
        return save(office)
        .then(function(){ return fetch(employeesEndPoint); })
        .then(parse)
        .then(function(employees) {
            // link each employee to office
            // throw in a Promise.all([save(office), save(employee)]) if needed here
            return Promise.all(employees.map(function(employee) {
                return fetch(salaryEndpoint)
                .then(parse)
                .then(function(salaries) {
                    return Promise.all(salaries.map(function(salary) {
                        // link salary to employee
                        return save(employee);
                    }));
                });
            }));
        });
    }));
});
Run Code Online (Sandbox Code Playgroud)

在最里面的循环回调中,您已经获得了所有office,employeesalary可以根据您的喜好将它们相互链接。你无法真正避免这种嵌套。

您将收到大量保存结果数组或整个过程中任何错误的承诺。