2014-02-24 200 views
13

我不熟悉承诺和使用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 && res.statusCode !== 201 && res.statusCode !== 202) { 
      err = new Error("Unexpected status code: " + res.statusCode); 
      err.res = res; 
      return reject(err); 
     } 
     resolve(res, body); 
     }); 
    }); 
} 

任何了解,将不胜感激。

+0

您可能需要[请求 - 承诺](https://github.com/tyabonil/request-promise)。有了这个lib,你可以保存一些代码来将请求包装到承诺中。 –

回答

20

从每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 
0

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()也可能返回completely unrelated 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.prototype.then可以返回任何东西,甚至是不确定的,或者甚至是另一个承诺。然后,该值或解析的Promise的值将传递给下一个处理函数。