>接受一个文件(从HTTP“POST”),然后
>将文件写入Box.com存储库.
从HTTP“POST”消息中读取文件数据的Node.js代码完美地运行:
// ORIGINAL (non-Promise; parse only) app.post('/upload',function(req,res) { console.log('/upload...'); var form = new multiparty.Form (); form.parse(req,function(err,fields,files) { res.writeHead(200,{'content-type': 'text/plain'}); res.write('received upload:\n\n'); res.end(util.inspect({fields: fields,files: files})); });
问题是读取文件数据只是我需要做的几件事中的第一件,所有这些都涉及异步回调.所以我试图使用promises来序列化调用(根据需要优雅地处理错误):
var Promise = require('bluebird'); ... // IDEAL SOLUTION (using "promises") var data = {}; try { parsePostMsg(req,data)) .then(sendAck(res,data)) .then(writeTempFile()) .then(sendToBox()) .then(deleteTempFile()); } catch (e) { console.log("app.post(/upload) ERROR",e); deleteTempFile(); }
问题:
第一个函数parsePostMsg()本身有一个回调函数.永远不会被调用:
function parsePostMsg(req,data) { console.log("parsePostMsg..."); return new Promise(function(resolve,reject) { var form = new multiparty.Form (); form.parse(req,files) { data.fields = fields; // <-- This never gets called,so fields & files data.files = files; // never get initialized! }); }); }
问:我如何正确1)创建promise,然后2)调用parsePostMsg()以便3)form.parse()正确地沿链调用?
问:我是否正确地在正确的地方创造了“承诺”????
问:那么resolve()和reject()怎么样?他们在哪里适合?
================================================== ====================
附录:我尝试过很多东西,到目前为止还没有任何工作.
目标:使这些函数(及其相关的回调,如果适用)按此顺序运行:
> parsePostMsg(req,data)//等待“解析表单数据”回调完成
> sendAck(res,data)//同步
> writeTempFile(data)//构建HTTP消息,发送它,并等待来自远程服务器的响应
> deleteTempFile(data)//完成所有操作后进行清理
这是一个失败的例子:
/* * If the "timeout" values are the same (e.g. "10"),everything works fine. * * But if the timeout values are *different*,the order gets scrambled: * Invoking parsePostMsg... * ... OK ... * Done: data= {} * writeTemp@setting data.temp { temp: 'foo' } * sendAck@ackNowledging {} { temp: 'foo' } * deleteTempFile@callback: data.temp was foo * parsePostMsg@setting data.{fields,files} {} { temp: undefined,fields: [],files: [] } */ var Promise = require('bluebird'); var req = {},res = {},data = {}; var temp; function parsePostMsg(req,reject) { setTimeout(function() { data.fields = []; data.files = []; console.log("parsePostMsg@setting data.{fields,files}",req,data); resolve(); },35); }); } function sendAck(req,data) { console.log("sendAck..."); return new Promise(function(resolve,reject) { setTimeout(function() { console.log("sendAck@ackNowledging",5); }); } function writeTempFile(data) { console.log("writeTemp..."); return new Promise(function(resolve,reject) { setTimeout(function() { data.temp = "foo"; console.log("writeTemp@setting data.temp",2); }); } function deleteTempFile(data) { console.log("deleteTemp..."); return new Promise(function(resolve,reject) { setTimeout(function() { console.log("deleteTempFile@callback: data.temp was ",data.temp); data.temp = undefined; resolve(); },15); }); } console.log("Invoking parsePostMsg..."); parsePostMsg(req,data) .then(sendAck(res,data)) .then(writeTempFile(data)) .then(deleteTempFile(data)); console.log("Done: data=",data);
解决方法
让我们看看这段代码:
parsePostMsg(req,data) .then(sendAck(res,data)) .then(writeTempFile(data)) .then(deleteTempFile(data)) // This console.log will execute way before // the promise is resolved console.log("Done: data=",data);
会发生什么是正确调用parsePostMsg(),但是在解析promise之前,所有事情都会执行.这是因为您实际上是在立即执行这些函数,然后这些执行的输出就是promise在解析时将尝试使用的内容.这就是为什么,如果你将parsePostMsg()中的超时设置为几秒钟,那么该函数的输出将被记录到最后.
所以这应该是这样的:
parsePostMsg(req,data) .then(sendAck) .then(writeTempFile) .then(deleteTempFile) .then(function () { // Now the console.log will log when everything is done. console.log("Done: data=",data); });
在这里,您告诉它承诺在promise解决时应该执行函数.但要做到这一点,我们必须以正确的方式建立承诺链.要将这些方法链接在一起,我们必须在前一个函数中返回我们想要在函数中使用的值.例如,我们必须在parsePostMsg()函数中返回sendAck()函数的参数.
让我们编写parsePostMsg,以便它返回链中所需的所有参数.
function parsePostMsg(req,res,data) { console.log("parsePostMsg..."); return new Promise(function (resolve,reject) { setTimeout(function () { data.fields = []; data.files = []; console.log("parsePostMsg@setting data.{fields,data); // Here we pass all the arguments into the resolve method // This means that the following then() call will receive // These argument. Take note that this is an array. resolve([req,data]); },3000); }); }
现在我们更改了parsePostMsg,以便它将在链中传递所有它的参数.让我们以同样的方式改变其他方法.
function sendAck(req,data) { console.log("sendAck..."); return new Promise(function (resolve,reject) { setTimeout(function () { console.log("sendAck@ackNowledging",data); resolve([req,3000); }); } function writeTempFile(req,data) { console.log("writeTemp..."); return new Promise(function (resolve,reject) { setTimeout(function () { data.temp = "foo"; console.log("writeTemp@setting data.temp",3000); }); } function deleteTempFile(req,data) { console.log("deleteTemp..."); return new Promise(function (resolve,reject) { setTimeout(function () { console.log("deleteTempFile@callback: data.temp was ",data.temp); data.temp = undefined; resolve([req,3000); }); }
现在注意所有函数都接受3个参数,但我们用数组调用resolve方法.如果我们只是简单地使用.then(),那么它将无法正常工作,但bluebird提供了一个名为.spread()的特殊辅助方法,它解析数组并使用数组的所有成员调用该方法.请注意,如果您使用的是ES2015,则可以使用ES2015进行破坏而不是使用.spread().
因此,使用.spread()代码应如下所示:
parsePostMsg(req,data) .spread(sendAck) .spread(writeTempFile) .spread(deleteTempFile) .spread(function (req,data) { // Now the console.log will log when everything is done. console.log("Done: data=",data); });
这是你提供正确工作的失败示例:
var Promise = require('bluebird'); var req = {},3000); }); } function sendAck(req,3000); }); } console.log("Invoking parsePostMsg..."); parsePostMsg(req,data) { console.log("Done: data=",data); }) .catch(function(err) { // Always put a .catch() at the end of your promise chains,ALWAYS,// it is literally the ultimate method to handle promise errors. console.warn(err); });
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。