我发现各种 Deferred/promise 库的文档通常涵盖非常简单的用例,例如链接 1 或 2 个函数/方法并导致解决或拒绝成功或错误。
但是,当涉及到更复杂的用例(5 个以上函数/方法的链;嵌套的 Deferreds;从其他 Deferreds 内部返回 Promise)时,我会空手而归,并变得非常沮丧。
例如,我有一个包含 2 个嵌套函数的函数。每个子函数都返回一个 promise ,我希望父函数返回子函数的成功/失败结果:
var saveUser = function(user) {
var saveNewUser = function(user) {
var deferred = when.defer();
user.save(function (err) {
if (err) {
deferred.reject();
}
else {
// forcing a rejection here for testing purposes
deferred.reject(6);
}
});
return deferred.promise;
}
var supplyUserCollections = function() {
var deferred = when.defer();
deferred.reject();
return deferred.promise;
}
return saveNewUser(user).then(supplyUserCollections(), function() {
console.log('failed to save new user');
}).then(function(data) {
console.log('succeeded to do everything');
}, function() {
console.log('failed to seed new user collections');
});
}
这不起作用;奇怪的是,“成功完成所有操作”console.log
会触发,即使我强制拒绝/失败两个子函数。看到 .then
上的第一个参数是成功的案例,我真的不明白为什么会发生这种情况。此外,假设父函数 saveUser
是另一个广泛的 promise 链的一部分,如下所示:
dropExistingCollections(collections).then(saveEntities(albums), function() {
console.log('failed to drop existing collections');
}).then(saveEntities(movies), function() {
console.log('failed to save all albums');
}).then(saveEntities(games), function() {
console.log('failed to save all movies');
}).then(saveUsers(users), function() {
console.log('failed to save all games');
}).then(function(data) {
console.log(data);
console.log('successfully saved all seed data');
res.send('database data wiped and re-seeded');
}, function() {
console.log('failed to save all users');
});
我不太确定如何以可与其余函数链接的方式正确地从 saveUser
返回 promise ,这些函数都是返回已解决/拒绝的 Deferred 的简单函数。
我真的很想更清楚地了解如何处理这些更复杂的 Deferreds/promise 用例。这显然是一个极其复杂的话题,而且我发现的大部分 Material 并没有引起我的共鸣。
最佳答案
始终从同步代码开始。它更容易理解,并且转换为异步代码从来没有那么困难。如果您包含了如何编写同步代码,而不仅仅是一些稍微损坏的异步代码,那么我会更容易地弄清楚您想要代码做什么。
简短回答
您最初的问题可能只是您在无意的地方添加了括号。您应该始终将函数传递给您的then
处理程序:
return saveNewUser(user).then(supplyUserCollections /* NOTE: no parenthesis */, function() {
console.log('failed to save new user');
}).then(function(data) {
console.log('succeeded to do everything');
}, function() {
console.log('failed to seed new user collections');
});
这似乎也是您对第二个函数的主要误解。
长答案
想象一下您要编写的代码可能类似于以下内容(如果用户有 saveSync
方法以及 save
方法)。
function saveNewUser(user) {
var result = user.saveSync();//may throw
// forcing a throw here for testing purposes
throw 6;
}
function supplyUserCollections() {
throw new Error('failed supplyUserCollections');
}
function saveUser(user) {
try {
saveNewUser(user);
} catch (ex) {
console.log('failed to save new user');
return;
}
try {
supplyUserCollections();
} catch (ex) {
console.log('failed to seed new user collections');
return;
}
console.log('succeeded to do everything');
}
现在我们可以非常简单地转换 saveNewUser
和 supplyUserCollections
:
function saveNewUser(user) {
var deferred = when.defer();
user.save(function (err) {
if (err) {
deferred.reject();
}
else {
// forcing a rejection here for testing purposes
deferred.reject(6);
}
});
return deferred.promise;
}
function supplyUserCollections() {
var deferred = when.defer();
deferred.reject();
return deferred.promise;
}
完成此操作后,我们只需要转换更复杂的 saveUser
方法:
function saveUser(user) {
saveNewUser(user)
.then(function () {
//this only happens if `saveNewUser` succeeded, like the bit after
//a catch block containing a `return`
return supplyUserCollections()
.then(function () {
console.log('succeeded to do everything');
}, function (ex) {
console.log('failed to seed new user collections');
})
}, function (ex) {
//this happens when `saveNewUser` failed (just like the catch block)
console.log('failed to save new user');
})
}
现在在我看来,同步函数的更可能的版本可能是这样的:
function saveUser(user) {
saveNewUser(user);
supplyUserCollections();
console.log('succeeded to do everything');
}
你可以写成:
function saveUser(user) {
saveNewUser(user)
.then(function () {
//this only happens if `saveNewUser` succeeded
return supplyUserCollections()
})
.then(function () {
//this happens when both methods succeeded
console.log('succeeded to do everything');
})
}
关于javascript - 更复杂的延迟/ promise 使用和链只是不点击。希望得到一些澄清,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17517593/