Javascript 如何正确地将承诺与嵌套链接起来
我的节点项目当前包含一个嵌套回调的横向圣诞树,以便获取数据并以正确的顺序处理它们。现在我正在尝试使用承诺重构,但我不确定如何正确地进行重构 比如说,我将获取一份办公室列表,然后是每个办公室的所有员工,然后是每个员工的工资。最终,所有实体(办公室、员工和工资)都应链接在一起并存储在数据库中 一些说明我当前代码的伪代码(省略错误处理): 我试着用承诺来解决这个问题,但我有几个问题:Javascript 如何正确地将承诺与嵌套链接起来,javascript,node.js,promise,Javascript,Node.js,Promise,我的节点项目当前包含一个嵌套回调的横向圣诞树,以便获取数据并以正确的顺序处理它们。现在我正在尝试使用承诺重构,但我不确定如何正确地进行重构 比如说,我将获取一份办公室列表,然后是每个办公室的所有员工,然后是每个员工的工资。最终,所有实体(办公室、员工和工资)都应链接在一起并存储在数据库中 一些说明我当前代码的伪代码(省略错误处理): 我试着用承诺来解决这个问题,但我有几个问题: 有点冗长 每个办公室都需要链接到各自的员工,但在saveEmployees功能中,我只能访问员工,而不能从链的更高层
- 有点冗长李>
- 每个办公室都需要链接到各自的员工,但在
功能中,我只能访问员工,而不能从链的更高层访问办公室:saveEmployees
这是改变这种状况的好办法
if (response.statusCode !== 200) {
reject(statusCode);
}
resolve(data);
对此
if (response.statusCode !== 200) {
return reject(statusCode);
}
resolve(data);
在您的示例中,结果是相同的,但是如果您正在做更多的事情(比如在数据库中做一些事情),则可能会出现意外的结果,因为如果不返回,整个方法将被执行
这个例子
var prom = new Promise((resolve,reject) => {
reject(new Error('error'));
console.log('What? It did not end');
resolve('Ok, promise will not be called twice');
});
prom.then(val => {
console.log(val);
}).catch(err => {
console.log(err.message);
});
有这个输出吗
What? It did not end
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);
});
您的预期功能
获取
、解析
、保存办公室
和保存员工
都很好。有了这些,您可以重构当前代码以使用承诺、链而不是嵌套(如果适用),并省去一堆错误处理样板文件:
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);
}));
});
}));
});
}));
});
在最内部的循环回调中,您可以使用所有的office
、employee
和salary
将它们链接到您喜欢的位置。你无法真正避免这种嵌套
您将得到一个承诺,即存储结果的大量数组或整个过程中的任何错误。听起来您想要嵌套三个循环。不,没有嵌套就没有理由这样做。你使用的是什么承诺库?这个问题不属于这个网站吗?我建议你阅读这篇关于承诺的文章,它将帮助你找到一个解决方案,如果你有机会再次重构,我建议你使用异步。检查这个,它比较了关于JavaScript回调地狱的几种方法。不,不要使用全局变量。请要做到这一点,必须使用承诺。
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);
});
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);
}));
});
}));
});
}));
});