2015-01-03 43 views
0

我正在用Parse's Cloud Code編寫一個函數,用5張撲克牌填充服務器。這個想法是,服務器應該等到所有5張卡片都在數據庫中,然後才能進入功能的下一部分(目前它只是向控制檯輸出一條消息。)我的承諾是否按預期工作?

我所看到的是所有5卡被添加到數據庫中,也並不一定出現在序列數據庫中,這使我相信他們是正確的被異步補充說。而對於mostpart我的記錄顯示預期行爲。

I2015-01-03T17:08:01.244Z] Attempting to create cards x5 
I2015-01-03T17:08:01.245Z] Attempting to save card0 
I2015-01-03T17:08:01.247Z] Attempting to save card1 
I2015-01-03T17:08:01.248Z] Attempting to save card2 
I2015-01-03T17:08:01.249Z] Attempting to save card3 
I2015-01-03T17:08:01.250Z] Attempting to save card4 
I2015-01-03T17:08:01.352Z] Card saved:4 
I2015-01-03T17:08:01.353Z] Card saved:4 
I2015-01-03T17:08:01.354Z] Card saved:4 
I2015-01-03T17:08:01.355Z] Card saved:4 
I2015-01-03T17:08:01.356Z] Card saved:4 
I2015-01-03T17:08:01.357Z] ALL 5 Promises theoretically fulfilled 

然而,請注意,當卡實際保存時,其中每個卡的日誌都使用相同的編號 - 在此情況下,「卡已保存:4」。

問題是......我的承諾是否按預期工作?以及如何修復我的錯誤以顯示已保存的實際卡號?

這裏是我的代碼:

Parse.Cloud.define("populateServer", function(request, response) 
{ 
    console.log("Attempting to create cards x5"); 
    var promises = createCards(5); 

    Parse.Promise.when(promises).then(function(result) 
    { 
     console.log("ALL 5 Promises theoretically fulfilled"); 
    }); 
}); 

function createCards(qty) 
{ 
    var promises = []; 

    for (i=0;i<qty;i++) 
    { 
     var Card = Parse.Object.extend("Card"); 
     var card = new Card(); 

     card.set("name", "test"); 
     card.set("number", i); 

     console.log("Attempting to save card" +i); 

     var promise = card.save(); 

     promises.push(promise); 

     promise.then(function() { 
      console.log("Card saved:" +i); 
     }, function(error) { 
      console.log("Uh oh, something went wrong."); 
     }); 
    } 
    return promises; 
} 

回答

2

你居然得到你想要的行爲,但i總是4在你的承諾結束,因爲它是之前任何then處理地執行遞增(您for循環是同步的,但你的處理程序是異步的)。

傳遞給all的通常承諾沒有同步解析,但由於您在創建每個承諾的鏈接時,您的調用只會在前一個承諾完成後觸發。

在一個側面說明:我不是超級熟悉解析的承諾的實現,但你也許可以救自己創建一個額外的數組,並從你的函數只是返回的承諾鏈調用Parse.Promise.when

function createCards(qty) { 
     // create a resolved promise that starts the "chain" 
     // for Parse prommises use Parse.Promise.as(); 
     var promiseChain = Parse.Promise.as(); 

     // start the for loop 
     for (i=0;i<qty;i++) { 
     // add another promise onto our chain 
     // you can `then` or `catch` off of this 
     // now if you want 
     promiseChain = promiseChain.then(function() { 
      // ... any additional logic 
      card.save(); 
     }); 
     } 

     return promiseChain; 
} 

// usage 
createCards(5) 
    .then(function() { 
    console.log('finished'); 
    }); 
+0

謝謝!我不知道如何創建承諾鏈並在循環中使用它們,這非常有用! –

2

由於Nick說,你的計數器(i)在執行任何then處理程序之前增加到4,因此所有處理程序自然使用最終值i(它是4)。

解決此問題的最快解決辦法可能是將閉包中的then處理程序的分配放在其中,在該閉包中可以使用變量記住調用閉包時的值i

例如,更換此:

promise.then(function() { 
    console.log("Card saved:" +i); 
}, function(error) { 
    console.log("Uh oh, something went wrong."); 
}); 

有了這個:

(function(){ 
    var myIndex = i; 
    promise.then(function() { 
     console.log("Card saved:" + myIndex); 
    }, function(error) { 
     console.log("Uh oh, something went wrong."); 
    }); 
})(); 

我做了一對夫婦撥弄在行動中看到的區別:Without closure - With closure

+0

謝謝!這看起來很有用,但我不完全理解它。 (function(){})如果它不在promise.then()方法中,它是如何調用的? –

+1

@ mac_55該函數被立即調用,注意函數類似於'(function(){...})()' 。第一對圓括號'(function(){...})'創建一個(匿名)函數,第二對(緊接着)表示它被執行。第一對圓括號實際上是可選的(你也可以編寫'function(){...}()'),但是它被用作約定來明確該函數是要立即執行的。谷歌爲「JavaScript自我調用功能」,你會發現很多解釋,其中一些是很好的。 – abl