javascript – 我只是没有得到ES6“承诺”

我正在编写一个Node.js应用程序:

>接受一个文件(从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);
    });

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...