【问题标题】:Modular promises and Promise.all()模块化承诺和 Promise.all()
【发布时间】:2017-06-10 01:16:39
【问题描述】:

我有一堆函数返回我想要概括的承诺,所以我这样写:

function checkWebpageForReference(data){
    //checks a webpage for the reference in html
    var promise = new Promise(function(resolve,reject){
        fetchUrl(data.url, function(err, meta, body){
            if (err) { reject(err); } else {
                console.log(body)
                if (body.toString().indexOf(data.text) !== -1){
                    resolve(data);
                } else {
                    reject("Could not find quote");
                }
            }
        });
    });
    return promise;
}

function takeScreenshot(data){
    //takes a screenshot of a webpage and saves it to the file system
    //TODO: Mouse coordinates
    data.id = shortid.generate();
    data.filename = data.id+'.png';
    var promise = new Promise(function(resolve,reject){
        webshot(data.url, data.filename, { shotOffset: {left: data.mouseX, top: data.mouseY} }, function(err) {
            if (err) { reject(err); } else {
                resolve(data);   
            }
        });
    });
    return promise;
}

function uploadReferencePictureToS3(data){
    //uploads a picture to S3
    var promise = new Promise(function(resolve, reject){
        s3.putObject({
            ACL: 'public-read',
            Bucket: S3_BUCKET,
            Key: data.id,
            Body: data.picturedata,
            ContentType: "image/jpg"
        }, function(err) {
            if (err) { reject(err); } else {
                resolve(data);   
            }
        }); 
    });
    return promise;
}

function saveNewReferenceToDb(data){
    //saves a new Reference to the database
    var promise = new Promise(function(resolve, reject){
        new Reference({
            _id: data.id,
            url: data.url,
            text: data.text,
            screenshot_url: AWS_S3_URL + data.id,
            created_by: "Daniel"
        }).save(function(err, saved){
            if (err) { reject(err); } else {
                data.newReference = saved;
                resolve(data);   
            }
        });
    });
    return promise;
}

function readFile(data){
    //reads a file from the file structure and stores it in a variable
    var promise = new Promise(function(resolve,reject){
        console.log(data);
        fs.readFile(data.filename, function(err, picturedata){
            console.log(picturedata);
            if (err) { reject(err); } else {
                data.picturedata = picturedata;
                resolve(data);   
            }
        }) ;
    });
    return promise;
}

function deleteFile(data){
    //deletes a file from the file structure
    var promise = new Promise(function(resolve, reject){
        fs.unlink(data.filename);
        resolve(data);
    });
    return promise;
}

我在每个函数中解析数据,因为我计划有很多这些类型的函数,而且我不知道在链接时它们将被调用的顺序:

readfile(somedata)
.then(upload)
.then(delete)
.then(save)
//etc

这工作正常,直到我必须做 Promise.all:

   Promise.all([
        referenceTools.checkWebpageForReference(req.body),
        referenceTools.takeScreenshot(req.body)
    ])
    .then(function(results){
        utils.readFile(results[1])
        .then(referenceTools.uploadReferencePictureToS3)
        .then(utils.deleteFile)
        .then(referenceTools.saveNewReferenceToDb)
        .then(function(data){
            res.json(data.newReference);
        })
        .catch(function(err){
            utils.errorHandler(err);
            res.send("There was an internal error. Please try again soon.");
        });  
    })
    .catch(function(err){
        utils.errorHandler(err);
        res.send("There was an internal error. Please try again soon.");
    });
    //my very ugly way of doing it

使用Promise.all().then(upload) 会给我带来错误,因为 Promise.all() 返回的新承诺是一个包含来自checkWebpageForReference 和takeScreenshot 的分辨率的对象。本质上,在readFile 中,我无法访问data 字段,因为生成的承诺是[data, data]。

有没有我可以遵循的模式来帮助我完成我需要做的事情?我需要将 Promise 模块化,为它们提供尽可能多的数据。

【问题讨论】:

  • 那么,您的每个函数都遵循一些通用接口吗?即prf1 和prf2 都返回包含new_variable1 的对象?如果不是,如果prf3 不知道它收到了什么,你怎么能让它保持一致?
  • @MattWay 他们并没有真正遵循的模式。我在链接时将其留给他们使用。我意识到这很容易出错,但我还没有找到更好的方法。这些函数只是假设data 包含他们要求的字段。如果链条设计得好,那么他们会的。但我不确定如何标准化。
  • 您能举个例子说明您希望prf3 的内部外观吗?
  • 因为您使用相同的对象引用作为每个函数的输入,所以您上面的示例不应该工作吗?通过抓取results[1],您不只是选择[相同] 引用之一吗?
  • @MattWay 它确实有效,但我担心它会在未来引起混乱或问题。如果 Promise.all() 中的一个函数返回一个字段而另一个没有返回,反之亦然,那么很难弄清楚该怎么做。我想我要的是一种方法来跟踪在链接承诺时传递的变量,同时在使用 Promise.all 时是安全的

标签: javascript design-patterns promise es6-promise


【解决方案1】:

你可以像这样.map()他们:

Promise.all(...)
  .then(datas => Promise.all(datas.map(upload)));

由于您在服务器端,我强烈推荐 Bluebird 作为原生 Promises 的替代品。然后你可以这样做:

Promise.all(...)
  .map(upload);

【讨论】:

  • 请注意,这会等待每一步都赶上所有内容。首先映射和 Promise.all 最后映射通常更快,允许所有步骤为每个文件并行运行。例如:Promise.all(files.map(file => readfile(file).then(upload).then(delete).then(save))).then(d‌​atas => ...)
猜你喜欢
  • 2016-11-25
  • 2017-05-17
  • 1970-01-01
  • 2020-04-24
  • 2022-08-20
  • 2020-02-29
  • 1970-01-01
  • 1970-01-01
  • 2018-05-03
相关资源
最近更新 更多