Удаление вложенных обещаний

#javascript #node.js #asynchronous #firebase-authentication

#javascript #node.js #запрос #обещание

Вопрос:

Я новичок в promises и пишу сетевой код, используя запросы и обещания в NodeJS.

Я хотел бы удалить эти вложенные обещания и вместо этого связать их в цепочку, но я не уверен, как бы я это сделал / правильно ли это.

 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);
                    });
            });
    });
};
  

Это код запроса:

 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 amp;amp; res.statusCode !== 201 amp;amp; res.statusCode !== 202) {
          err = new Error("Unexpected status code: "   res.statusCode);
          err.res = res;
          return reject(err);
        }
        resolve(res, body);
      });
    });
}
  

Любая информация будет оценена.

Комментарии:

1. Возможно, вас заинтересует Request-Promise . С помощью этой библиотеки вы сохраняете некоторый код для преобразования запроса в обещание.

Ответ №1:

При каждом then обратном вызове вам нужно будет возвращать новое обещание:

 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);
      });
};
  

Обещание, возвращаемое .then() вызовом, затем будет разрешено значением из «внутреннего» обещания, чтобы вы могли легко связать их.

Общий шаблон:

 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
  

Ответ №2:

Promise.prototype.then предназначен для возврата другого обещания, чтобы вы могли связать их.

Переданная функция обработчика .then() может возвращать обычное значение, например число, строку или объект, и это значение будет передано следующему обработчику .then() .

Одним из вариантов является наличие boxViewerRequestSync синхронной функции, которая возвращает response объект:

 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);
    })
  

Но, конечно, ваш boxViewerRequest является асинхронным и вместо этого возвращает обещание. В этом случае функция-обработчик, переданная в .then() , также может возвращать совершенно не связанные Promise . Это новое обещание выполняется синхронно, и как только оно разрешено / отклонено, его результат передается следующему обработчику.

 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);
    })
  

Отслеживание всех обещаний сбивает с толку, но суть в следующем: Promise.prototype.then всегда будет возвращать объект Promise, но переданная функция-обработчик Promise.prototype.then может возвращать что угодно, даже неопределенное, или даже другое обещание. Затем это значение или значение разрешенного обещания передается следующей функции-обработчику.