2015-09-24 29 views
1

我遇到了调用promises/functions的顺序问题。基本上我获取一个ID数组,然后,对于每个ID,想要获取订单详细信息并保存。然后转到下一个ID。到现在为止,直到每个订单明细都被提取之后,它才会保存。Promises的顺序调用

代码:

// Convenience function 
var fetchOrders = function() { 
    return self.fetchOrderList() 
    .then(function(orders) { 
     return P.map(orders, function(r) { 
     return self.fetchOrderById(r.id).then(fn); 
     }); 
    }); 
}; 

// Fetch initial order list 
var fetchOrderList = function() { 
    return new P(function(resolve, reject) { 
    debug('Fetching initial list'); 
    resolve([{ 
     id: 123 
    }, { 
     id: 134 
    }, { 
     id: 1333 
    }]); 
    }); 
}; 


var fetchOrderById = function(id) { 
    return new P(function(resolve, reject) { 
    debug('Fetching by ID'); 
    resolve({ 
     foo: 'bar' 
    }); 
    }).then(function(o) { 
    debug('Saving'); 
    return o; 
    }) 
}; 

fetchOrders(); 

预期结果:

Fetching initial list 
Fetching by ID 
Saving 
Fetching by ID 
Saving 
Fetching by ID 
Saving 

实际结果

Fetching initial list 
Fetching by ID 
Fetching by ID 
Fetching by ID 
Saving 
Saving 
Saving 
+0

请说明所需的执行顺序是什么。你首先得到一个订单ID列表,然后你必须得到每个细节并将这些细节保存到数据库中。你想要什么操作并行运行,哪个运行顺序?而且,你提到节流 - 你想扼杀什么(通常意味着减慢)?而且,为什么你要在'doCall()'内重新分配'queue',但是从来没有使用过重新分配的变量 - 那是什么意思?而且,延迟的重点是什么?而不是描述你的代码(这对我来说似乎过于复杂),请描述一个你想要的简单规范。 – jfriend00

+0

该队列工作正常 - 每次调用“doCall”应该在队列中运行。期望如上所列。 1)获取ID数组(排队)。 2)对于每个ID轮流进行排队调用以获取详细信息并将详细信息保存到db(虚拟调用)。这不是正在发生的事情。它不会做数据库调用,直到初始数组中的每个条目都已获取细节。 – cyberwombat

+0

对不起,你可能很容易看到你想要的东西,这听起来像是一个迷人的问题来解决,但我真的不明白你想要什么。我希望看到没有提及现有代码的情况下所需确切结果的规范描述。 – jfriend00

回答

1

OK,我明白为什么它做它在做什么。首先,我将解释为什么,然后讨论可能的变化。

在您的测试代码并没有为P.map()设置选项,它会同步调用所有的fetchOrderById()操作此起彼伏所以他们都将是在同一时间飞行(如果他们是真正的异步操作)。

因此,您已经启动了所有订单的ID操作的所有提取操作。然后,随着每一项决议,他们将运行保存。在测试代​​码中,他们都立即解决。但是,通过Promise规范,所有.then()处理程序异步调用后,所有同步代码已解开并完成(技术上,我认为它使用类似nextTick()来安排每个.then()处理程序)。

因此,您看到所有通过ID进行的提取都会同步解决,这会将所有保存操作排队以在nextTick中运行。因此你可以得到你看到的实际结果。

如果fetchByOrderId()实际上是异步的(稍后解析它),您仍然会看到所有提取都立即开始 - 所有这些请求都会启动,然后当每次按id提取时都会保存。

如果你真的想把它改成ID/save提取,按ID/save提取,按ID/save提取,我可以想出一个很好的方法来构造它,但这必然会对所有的操作和需要更长时间才能完成(无并行网络操作)。

仅供参考,我把你的代码放到一个正在运行的jsFiddle中进行测试:http://jsfiddle.net/jfriend00/k49qbd3z/。我只需要删除一个.then(fn),因为您提供的代码中没有这样的fn


您可以通过添加{concurrency: 1}P.map(),迫使它一次只能做一个操作得到所要求的输出。

// Convenience function 
var fetchOrders = function() { 
    return fetchOrderList().then(function(orders) { 
     return P.map(orders, function(r) { 
     return fetchOrderById(r.id); 
     }, {concurrency: 1}); 
    }); 
}; 

看到这里的工作演示:这种输出http://jsfiddle.net/jfriend00/wshLu0g5/

Fetching initial list 
Fetching by ID 
Saving 
Fetching by ID 
Saving 
Fetching by ID 
Saving 

请记住,因为你所有的序列化通过id获取并保存到只有这可能会严重减缓的最终结果一次一个操作。获取一个id的数据,然后保存它,然后获取下一个id的数据,然后保存它,然后获取下一个id的数据,然后保存它,等等。

+0

新增解决方案以获得所需的输出订单。 – jfriend00