2014-09-30 74 views
0

我試圖從LocalForage庫鏈接多個getItem承諾,這些密鑰是從數組中讀取的。來自LocalForage for JavaScript循環的JavaScript鏈接承諾

問題: 我需要Resolve或Reject回調觸發所有LocalForage承諾完成後。

這兩種方法都沒有正確的調用堆棧。有任何想法嗎?

CODE 1:

function load(keyHandlerPairs, correct, incorrect) { 
    var result = { 
        resolved: 0, 
        rejects: 0, 
       }, 
       p = new Promise(function (resolve, reject) { 
        //Retrieve objects from localstorage; 
        if ($.isArray(keyHandlerPairs)) { 
         for (var i = 0; i < keyHandlerPairs.length; i++) { 
          var kv = keyHandlerPairs[i]; 
          lf.getItem(kv.key, kv.handler).then(
           //Resolved 
           function() { console.log('resolved'); result.resolved++; } 
          ); 
         } 
        } else { 
         var kv = keyHandlerPairs; 
         lf.getItem(kv.key, kv.handler); 
        } 


        if ((result.resolved + result.rejects) == keyHandlerPairs.length) { 
         console.log(result.resolved, result.rejects, keyHandlerPairs.length); 
         resolve(result); 
        } else { 
         console.log(result.resolved, result.rejects, keyHandlerPairs.length); 
         reject(result); 
        } 
       }).then(correct, incorrect); 
} 

CODE ALT:

if ($.isArray(keyHandlerPairs)) { 
         var promises = []; 
         for (var i = 0; i < keyHandlerPairs.length; i++) { 
          var kv = keyHandlerPairs[i]; 
          promises.push(lf.getItem(kv.key, kv.handler)); 
         } 

         Promise 
          .all(promises) 
          .then(function (value) { console.log(value); result.resolved++; }) 
          .catch(function (error) { console.log(error); result.rejects++; }); 

        } else { 
         var kv = keyHandlerPairs; 
         lf.getItem(kv.key, kv.handler); 
        } 
+0

你是否真的試圖連續鏈接它們,還是並行執行它們? – Bergi 2014-09-30 18:36:04

+0

我假設你使用Mozilla的ES6'Promise'? – Bergi 2014-09-30 18:37:52

+0

是的,我想讓它們平行鏈接。我希望當這些承諾中的每一個都完成時履行承諾。 – 2014-09-30 20:21:37

回答

1

我需要解決或拒絕回調觸發後,所有的LocalForage承諾完成。

是的。 lf.getItem是異步的,但您在發起所有呼叫之後立即測試(result.resolved + result.rejects) == keyHandlerPairs.length.resolved.rejects仍然是0(請注意,您永遠不會增加拒絕次數)。

首先,您不應該使用Promise構造函數,而是爲尚未支持承諾的單個異步API構造承諾。應該沒有邏輯,只是一個普通的電話。假設您想使用Promise.all來等待所有同時運行的promise,並將它們的組合結果作爲數組的承諾。您的代碼應該是這樣的:

if (!$.isArray(keyHandlerPairs)) 
    keyHandlerPairs = [keyHandlerPairs]; 
var promises = keyHandlerPairs.map(function(kv) { 
    return lf.getItem(kv.key, kv.handler); 
}); 
return Promise.all(promises); 

好了,現在假設你其實並不關心結果和所有的承諾是否成功,但只有約的兌現VS拒絕承諾的數字。好的,這裏沒有本地組合函數,所以我們需要編寫我們自己的(並使用構造函數Promise)。但是,此功能應該是通用並且與鍵值處理程序對無關。

Promise.countResolutions = function(promises) { 
    var result = {fulfillments:0, rejections:0}, 
     len = 0; 
    return new Promise(function(resolve, reject) { 
     function addResult(type) { 
      result[type]++; 
      if (result.fulfillments+result.rejections == len) 
       resolve(result); 
      return true; 
     } 
     try { 
      let i = 0; 
      for (let promise of promises) { 
       let called = false; 
       i++; 
       promise.then(function onfulfilled() { 
        if (!called) called = addResult("fulfillments"); 
       }, function onrejected() { 
        if (!called) called = addResult("rejections"); 
       }); 
      } 
      len = i; 
      if (result.fulfillments+result.rejections == len) 
       resolve(result); 
     } catch (e) { 
      reject(e); 
     } 
    }); 
}; 

是的,它不像它看起來那麼微不足道(好吧,也許上面的版本有點太詳細)。但是,一旦你有了這個,你可以簡單地用.countResolutions()代替第一個片段中的.all(),你會得到預期的結果。

+0

我有一個關於你的代碼的問題。你爲什麼用'let'代替'var'?他們之間有什麼區別? – 2014-10-01 14:51:48

+0

所以'let called'是for循環體的局部,而不是'function(resolve,reject){'scope作爲'var'的局部變量(參見http://stackoverflow.com/q/ 762011/1048572) – Bergi 2014-10-01 14:53:09

+0

Firefox v32似乎不支持使用'let'。使用該代碼時出現語法錯誤。所以我調整了你的計數承諾的方法(去掉了所謂的變量,更改了循環,更改了addResult),並且讓它起作用! FIDDLE:http://jsfiddle.net/t3v61te1/ – 2014-10-02 09:50:06