gpt4 book ai didi

javascript - 级联 promise

转载 作者:数据小太阳 更新时间:2023-10-29 04:42:17 24 4
gpt4 key购买 nike

任何超出简单 promise 的事情通常都会让我感到困惑。在这种情况下,我需要对 N 个对象连续执行 2 个异步调用。首先,我需要从磁盘加载一个文件,然后将该文件上传到邮件服务器。我更喜欢同时执行这两个操作,但我已经通过先执行所有读取然后再执行所有上传来使其正常工作。下面的代码有效,但我不禁认为它可以做得更好。我不明白的一件事是为什么 when.all 不拒绝。我对文档的解释似乎暗示,如果其中一个 promise 被拒绝,则 .all 将被拒绝。为了测试错误,我已经注释掉了较低的分辨率。没有错误,事情似乎工作正常并且有意义。

mail_sendOne({
from: 'greg@',
to: 'wilma@',
subject: 'F&B data',
attachments: [
{name: 'fred.html', path: '/fred.html'},
{name: 'barney.html', path: '/barney.html'}
]
})
.done(
function(res) {
console.log(res)
},
function(err) {
console.log('error ', err);
}
)

function mail_sendOne(kwargs) {
var d = when.defer();
var promises = [], uploadIDs = [], errs = [];

// loop through each attachment
for (var f=0,att; f < kwargs.attachments.length; f++) {
att = kwargs.attachments[f];

// read the attachment from disk
promises.push(readFile(att.path)
.then(
function(content) {
// upload attachment to mail server
return uploadAttachment({file: att.name, content: content})
.then(
function(id) {
// get back file ID from mail server
uploadIDs.push(id)
},
function(err) {
errs.push(err)
}
)
},
function(err) {
errs.push(err)
}
))
}

// why doesn't this reject?
when.all(promises)
.then(
function(res) {
if (errs.length == 0) {
kwargs.attachments = uploadIDs.join(';');
sendEmail(kwargs)
.done(
function(res) {
d.resolve(res);
},
function(err) {
d.reject(err);
}
)
}
else {
d.reject(errs.join(','))
}
}
)

return d.promise;
}

function readFile(path) {
var d = when.defer();
var files = {
'/fred.html': 'Fred Content',
'/barney.html': 'Barney Content'
}

setTimeout(function() {
d.reject('Read error');
//d.resolve(files[path]);
}, 10);

return d.promise;
}

function uploadAttachment(obj) {
var d = when.defer();

setTimeout(function() {
d.reject('Upload error');
//d.resolve(new Date().valueOf());
}, 10);

return d.promise;
}

function sendEmail(kwargs) {
var d = when.defer();

setTimeout(function(){
console.log('sending ', kwargs)
}, 5);

return d.promise;
}

最佳答案

有几个反模式使代码变得比它需要的更困惑。一种是在应该链接它们时在 .then 回调中使用 .then。另一个是 deferred antipattern .

首先,让我们分别为读取和上传创建一个函数,这两个函数都处理各自的错误并抛出一个带有更多上下文的新错误:

function readAndHandle(att) {
return readFile(att.path)
.catch(function (error) {
throw new Error("Error encountered when reading " + att.path + error);
});
}

function uploadAndHandle(att, content) {
return uploadAttachment({file: att.name, content: content})
.catch(function (error) {
throw new Error("Error encountered when uploading " + att.path + error);
});
}

然后,让我们将这两个组合成一个函数,该函数首先读取文件,然后上传文件。这个函数返回一个 promise :

// returns a promise for an uploaded file ID
function readAndUpload(att) {
return readAndHandle(att)
.then(function (content) {
return uploadAndHandle(att, content);
});
}

现在您可以使用 .map() 将您的附件数组映射到文件 ID 的 promise 数组:

var uploadedIdsPromise = kwargs.attachments.map(readAndUploadAsync);

这就是您可以传递给 when.all() 的内容。 .then 处理程序会将一组 ID 传递给它的回调:

return when.all(uploadedIdsPromise)
.then(function (ids) {
kwargs.attachments = ids.join(";");
return sendEmail(kwargs);
})
.catch(function (error) {
// handle error
});

这就是它的要点。

这里要注意的一件大事是,除了修改 kwargs 变量的一个地方外,promise 不会修改 promise 链之外的任何内容。这有助于保持逻辑清晰和模块化。

The Deferred Antipattern

请注意,上面的代码中没有d.resolved.reject。唯一应该使用 deferred 的时候是当您还没有可用的 promise 时(或在其他一些特殊情况下)。即便如此,现在也有一些首选的方式来创建 promise 。

when.js API 文档是这样说的:

Note: The use of when.defer is discouraged. In most cases, using when.promise , when.try , or when.lift provides better separation of concerns.

当前从一些非 promise 异步 API 创建 promise 的推荐方法是使用 revealing constructor pattern .以您的 uploadAttachment() 函数为例,它看起来像这样:

function uploadAttachment(obj) {
return when.promise(function (resolve, reject) {
setTimeout(function() {
resolve(new Date().valueOf());
// or reject("Upload error");
}, 10);
});
}

这就是 ES6 promise API 的工作方式,它使您不必在 deferred 对象周围乱七八糟。

关于javascript - 级联 promise ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27569830/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com