6

我有点开始学习javascript并且有一个关于将同步和异步调用组合到函数的问题。这只是一个理论问题,但我希望它能传达这个想法。

假设我们有一个 javascript 程序来决定我需要购买多少香蕉和橙子。

console.log('buy %d bananas and %d oranges', bananas, oranges)

现在,我可以决定我可以买多少香蕉,但我需要问我妻子她想要多少橙子,所以我给她发了短信。(我可以编写一个异步函数来表示这一点)。

这将是我的直接方法:

var bananas = 10;
var oranges = 0;
textWife('askAboutOranges',function(number){ oranges = number; }
console.log('buy %d bananas and %d oranges', bananas, oranges)

但对我来说这没有任何意义,因为我要等我老婆回复,所以我可能不会及时拿到橙子的数量。

所以我可以将我的程序更改为:

var bananas = 10;
var oranges = 0;
textWife('askAboutOranges',function(number){ 
   oranges = number;
   console.log('buy %d bananas and %d oranges', bananas, oranges); 
}

但我不喜欢这样,因为现在我有决定买什么的逻辑,包括香蕉,在我妻子的回应中。如果我决定不想要橘子怎么办,我是否必须这样做:

var bananas = 10;
var oranges = 0;
if (wantOranges)
{
  textWife('askAboutOranges',function(number){ 
   oranges = number;
   console.log('buy %d bananas and %d oranges', bananas, oranges); 
  }
}
else 
  console.log('buy %d bananas and %d oranges', bananas, oranges); 

所以我的问题是,谁能解释我做这样的事情的最好/正确的方法是什么?

4

5 回答 5

7

jQuery Deferred是一个很好的工具。我可能会做这样的事情来分离关注点:

function decideHowManyBananas() {
    return 10;
}

function decideHowManyOranges() {
    var deferred = $.Deferred();

    if (wantOranges) {
        textWife('askAboutOranges', function(number) { 
            deferred.resolve(number);
        });
    } else {
        deferred.resolve(0);
    }

    return deferred.promise();
}

$.when(decideHowManyBananas(), decideHowManyOranges()).done(function(bananas, oranges) {
    console.log('buy %d bananas and %d oranges', bananas, oranges);
});
于 2013-07-09T23:00:41.033 回答
3

没有正确/最好的方法 - 它总是取决于。现代 Javascript 库使用 Deferreds 和 Promises 等概念在多个异步调用、同步调用和即时数据之间进行同步。使用 jquery,您的代码可能会写成:

$.when({bananas:10, oranges:1}, textWife('askAboutOranges')).done(function(myList, herList) {
    buyBananas(myList.bananas);
    buyOranges(myList.oranges + herList.oranges);
});

有关详细信息,请参阅http://api.jquery.com/category/deferred-object/

这就是如何在代码中以一种优雅的方式创建 Deferred 对象:

function decideHowManyOranges() {
    if (!wantOranges)
        return 0;
    return $.Deferred(function(d) {
        textWife('askAboutOranges', function(number) {
            d.resolve(number);
        })
    })
}

numOfBananas = 10

$.when(numOfBananas, decideHowManyOranges()).done(function(bananas, oranges) {
    console.log('buy %d bananas and %d oranges', bananas, oranges);
});
于 2013-07-09T22:46:09.223 回答
1

承诺

// setup
var bananas = 4
var wantOranges = true
function textWife() { return new Promise((resolve, reject) => setTimeout(() => resolve(8), 1000)) }

// execution
Promise.all([
  bananas,
  wantOranges ? textWife() : 0 // ternary is necessary here because boolean logs as `NaN`
]).then(([bananas, oranges]) => console.log('buy %d bananas and %d oranges', bananas, oranges))

注意:我正在使用 ..
Promises
解构赋值,其中var [bananas, oranges] = [4, 8]var bananas = 4, oranges = 8.
箭头函数 () => {}

于 2017-11-08T11:03:24.537 回答
0

准备一个函数并在两种情况下都使用它来删除代码重复:

var bananas = 10;
var oranges = 0;
function buyStuff() {
  console.log('buy %d bananas and %d oranges', bananas, oranges); 
}
if (wantOranges)
  textWife('askAboutOranges',function(number){ 
    oranges = number;
    buyStuff();
  })
else 
  buyStuff();
于 2013-07-09T22:22:44.813 回答
0

在您的第一个示例中,您陈述了“我应该买多少香蕉和橙子?”这个问题的答案。取决于您拥有的信息,即需要的香蕉数量,以及您不拥有的信息,需要的橙子数量,因此您必须先获取缺失的信息才能回答。

然后,您重构代码以推迟回答您的问题,直到您拥有丢失的信息,这是解决这种依赖关系的典型方法。

然后你说这不能满足你,因为你可能根本不想购买任何橙子。这是一个新要求,因此使您原来的问题无效,将其更改为“我应该买多少香蕉?”

通过删除对缺失信息的要求,您更改了问题,因此需要将您的问题特殊情况下分成两个问题。

您提供的最终代码示例通过首先确定是否需要同时购买香蕉和橙子或购买橙子来做到这一点,这确实是解决问题的最直接方法。

于 2013-07-09T22:34:28.450 回答