Eliminar promesas anidadas
Soy nuevo en las promesas y en la escritura de código de red mediante solicitudes y promesas en NodeJS.
Me gustaría eliminar estas promesas anidadas y encadenarlas, pero no estoy seguro de cómo hacerlo o si es el camino correcto a seguir.
exports.viewFile = function(req, res) {
var fileId = req.params.id;
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
boxViewerRequest('documents', {url: response.request.href}, 'POST')
.then(function(response) {
boxViewerRequest('sessions', {document_id: response.body.id}, 'POST')
.then(function(response) {
console.log(response);
});
});
});
};
Este es el código de solicitud:
var baseContentURL = 'https://api.box.com/2.0/';
var baseViewerURL = 'https://view-api.box.com/1/';
function boxContentRequest(url, accessToken) {
return new Promise(function (resolve, reject) {
var options = {
url: baseContentURL + url,
headers: {
Authorization: 'Bearer ' + accessToken,
}
};
request(options, function (err, res) {
if (err) {
return reject(err);
} else if (res.statusCode !== 200) {
err = new Error("Unexpected status code: " + res.statusCode);
err.res = res;
return reject(err);
}
resolve(res);
});
});
}
function boxViewerRequest(url, body, method) {
return new Promise(function (resolve, reject) {
var options = {
method: method,
url: baseViewerURL + url,
headers: {
Authorization: 'Token ' + config.box.viewerApiKey
},
json: body
};
request(options, function (err, res, body) {
if (err) {
return reject(err);
} else if (res.statusCode !== 200 && res.statusCode !== 201 && res.statusCode !== 202) {
err = new Error("Unexpected status code: " + res.statusCode);
err.res = res;
return reject(err);
}
resolve(res, body);
});
});
}
Cualquier idea sería apreciada.
En cada then
devolución de llamada, deberás devolver la nueva promesa:
exports.viewFile = function(req, res) {
var fileId = req.params.id;
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequest('documents', {url: response.request.href}, 'POST');
})
.then(function(response) {
return boxViewerRequest('sessions', {document_id: response.body.id}, 'POST');
})
.then(function(response) {
console.log(response);
});
};
La promesa devuelta por la .then()
llamada se resolverá con el valor de la promesa "interna", de modo que pueda encadenarlas fácilmente.
Patrón genérico:
somePromise.then(function(r1) {
return nextPromise.then(function(r2) {
return anyValue;
});
}) // resolves with anyValue
||
\||/
\/
somePromise.then(function(r1) {
return nextPromise;
}).then(function(r2) {
return anyValue;
}) // resolves with anyValue as well
Promise.prototype.then
está diseñado para devolver otra promesa, para que puedas encadenarlas.
La función de controlador pasada .then()
puede devolver un valor normal , como un número, una cadena u un objeto, y este valor se pasará al siguiente controlador de .then()
.
Una opción es tener boxViewerRequestSync
una función síncrona que devuelva un response
objeto:
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequestSync('documents', {url: response.request.href}, 'POST')
})
.then(function(response) { // this `response` is returned by `boxViewerRequestSync`
return boxViewerRequestSync('sessions', {document_id: response.body.id}, 'POST')
})
.then(function(response) {
console.log(response);
})
Pero, por supuesto, boxViewerRequest
es asincrónico y, en su lugar, devuelve una promesa. En ese caso, la función de controlador pasada .then()
también podría devolver un archivoPromise
. Esta nueva promesa se ejecuta de forma sincrónica y, una vez resuelta/rechazada, su resultado se pasa al siguiente controlador.
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequest('documents', {url: response.request.href}, 'POST')
})
.then(function(response) { // this `response` is the result of resolving the promise returned by `boxViewerRequest`
return boxViewerRequest('sessions', {document_id: response.body.id}, 'POST')
})
.then(function(response) {
console.log(response);
})
Hacer un seguimiento de todas las promesas es confuso, pero la conclusión es la siguiente: siempre devolveráPromise.prototype.then
un objeto Promesa, pero la función de controlador pasada puede devolver cualquier cosa, incluso indefinida, o incluso otra Promesa. Luego, ese valor, o el valor de la Promesa resuelta, se pasa a la siguiente función de controlador.Promise.prototype.then