2014-06-21 54 views
1

我試圖用Q.js來處理在Web應用程序與promisesdeferrable一些問題 - 我會說我的理解async開始基本爲0現在。這是我第一次真正嘗試它,而且我真的即使在閱讀儘可能多的文檔後也會丟失。通過文件試圖循環與Q.js

我先前使用庫稱爲jsdeferred實現如下的代碼;它遍歷一系列文件並加載它們,並將它們添加到數組中。但是,因爲我已經知道我不應使用jsdeferred,我被告知我應該使用promisesdeferrables正確。

我已經探索了很多這方面的場地,我可能只是愚蠢的,但我有一個非常困難的時間實現這個確切的代碼在承諾導向庫(在這個例子中,我試圖用Q.js,與沒有成功)。

Q.js Library

define(function() { 
    return function (selector, callback) { 
     var files = [ 
      "/app_content/json/ecma5.json", 
      "/app_content/json/jquery.json", 
      "/app_content/json/tangent.json" 
     ]; 
     var results = []; 
     var editor, server; 

     return Deferred.loop(files.length, function (i) { 
      return $.get(files[i]).next(function(data) { 
       results.push(data); 
      }); 
     }).next(function() { 
      // a lot of things happen here. they are amazing things. 
     }).next(function() { 
      // seriously, this stuff is awesome. 
     }).next(function() { 
      callback(editor); 
     }); 
    }; 
}); 

我專門有一個非常艱難的時間與文件加載/循環,任何幫助,將不勝感激。我想,一旦我在這裏站穩腳跟,我將能夠更好地進行,但是這種文件循環真的讓我失望。我一直在閱讀文檔的一切似乎都是一次性使用場景。

我仍在閱讀文檔,我將繼續這樣做,但如果任何人都可以幫助我在這裏立足,我將不勝感激。一旦我看到它與我自己的東西一起工作,我就更容易接受其他情況。我有大約20個需要開始使用這個概念的地方,但這是第一個令我頭痛的地方。

更新

我不使用Q.js,它是剛來到最值得推薦的一個。如果它能解決我的問題,我也在尋找https://github.com/caolan/async

進一步更新

與文檔的更多,我已經合併的工作代碼的東西,但它似乎仍然失去了一些東西。我無法將results作爲參數傳遞給每個then(fn),我必須將其保留爲外部變量。

var results = []; 
var editor, server; 

var chain = files.reduce(function (previous, item) { 
    return previous.then(function(previousValue) { 
     return Q.resolve($.get(item, function(data) { 
      results.push(data); 
     })); 
    }); 
}, Q.resolve()); 

chain 
    .then(function (results) { 
    }) 
    .then(function (results) {  
     // I can't seem to get results to pass through the 2nd 'next'.   
    }) 
    .then(function() { 
     callback(editor); 
    }); 

最終結果

在大家的幫助下在這裏,我終於做出此代碼的工作我多麼希望。這是最終結果。這是CodeMirror使用tern和自定義腳本定義的實現。

define(function() { 
    return function (selector, callback) { 
     var editor, server, results, files = [ 
      "/app_content/json/ecma5.json", 
      "/app_content/json/jquery.json", 
      "/app_content/json/tangent.json" 
     ]; 

     Q 
      .all(files.map($.get)) 
      .then(function(data) { 
       results = data; 
      }) 
      .then(function() { 
       editor = CodeMirror.fromTextArea(selector[0], { 
        mode: { name: "javascript", globalVars: true }, 
        lineNumbers: true, 
        lineWrapping: true, 
        matchBrackets: true, 
        indentUnit: 2, 
        tabMode: "spaces", 
        autoCloseBrackets: true, 
        matchTags: true, 
        highlightSelectionMatches: true, 
        continueComments: "Enter", 
        foldGutter: true, 
        width: "100%", 
        gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], 
        extraKeys: { 
         "Ctrl-Space": "autocomplete", 
         "Ctrl-Q": function(cm) { cm.foldCode(cm.getCursor()); } 
        } 
       }); 
      }) 
      .then(function() { 
       server = new CodeMirror.TernServer({ 
        defs: results 
       }); 
       editor.setOption("extraKeys", { 
        "Ctrl-Space": function(cm) { server.complete(cm); }, 
        "Ctrl-I": function(cm) { server.showType(cm); }, 
        "Alt-.": function(cm) { server.jumpToDef(cm); }, 
        "Alt-,": function(cm) { server.jumpBack(cm); }, 
        "Ctrl-Q": function(cm) { server.rename(cm); }, 
       }); 
       editor.on("cursorActivity", function(cm) { server.updateArgHints(cm); }); 
      }) 
      .then(function() { 
       callback(editor); 
      }) 
      .done(); 
    }; 
}); 

我提供極端,極端感謝這裏提供的建設性的,有用的,有用的和知識淵博的信息。

+0

哇,很多很棒的答案。我已經嘗試過所有,他們都工作。我需要時間考慮哪一個我需要接受作爲正確的一個。 – Ciel

回答

2

使用Q.js,並假設你不需要與請求一起發送任何數據,你可以使用mapQ.all縮短代碼:

var results, 
    files = [ 
    "/app_content/json/ecma5.json", 
    "/app_content/json/jquery.json", 
    "/app_content/json/tangent.json" 
]; 

Q.all(files.map($.get)) 
    .then(function(_results) { 
     results = _results; 
    }) 
    .then(function () { 
     // More awesome stuff here 
    }) 
    .then(function() { 
     // etc... 
     console.log(results); 
    }) 
    .done(); 

注意,爲了使用results內隨後的.then()塊,您必須在promise鏈之外保存對它的引用。在你的例子中,你想要的results是你傳遞給then()的函數的本地 - 它影響了全球results。簡單地給它一個不同的名稱,如_results,然後將其分配給全局results以便稍後能夠使用它。

+0

我非常喜歡這個解決方案,它乾淨,優雅,易於閱讀。我真的很喜歡易於閱讀的代碼。我有幾個問題,如果你願意借你的時間 - 我注意到你的一行有'then(function =(){'但其他只是'.then(function(){'。Does the'=' '這裏提出了任何重要的東西,或者只是打字太快或者沒有想到的結果? – Ciel

+0

另外,你調用'.done();'作爲一個空方法,'done()'方法隱式地告訴'Q'整個'鏈'已經完成並且可以得出結論嗎?我問,因爲我有一些情況需要在兩個文件之間打開一個鏈,這是否可以使用類似的命令完成?我會提出另一個問題因此,如果你有這個答案,你可以得到適當的信貸 – Ciel

+0

@Ciel,在'then(function =(){'是額外的'='是一個錯字,它不應該在那裏(我編輯過),是的,調用'.done()'表示這個承諾鏈已經完成了。[黃金法則vs完成](https://github.com/kriskowal/q/wiki/API-Reference# promisedoneonfulfilled-onrejected-onprogress)要麼將您的承諾退還給其他人,要麼使用'done'來終止它。否則,未處理的拒絕將被無聲地吞噬。 –

2

試試這個

function readFile(file) { 
    var deferred = Q.defer(); 
    $.get(file, function(data) { 
     deferred.resolve(data); 
    }); 
    return deferred.promise; 
} 

var promises = []; 

var files = [ 
    "/app_content/json/ecma5.json", 
    "/app_content/json/jquery.json", 
    "/app_content/json/tangent.json" 
]; 

for(var i = 0; i < files.length; i++){ 
    promises.push(readFile(files[i])); 
} 

Q.all(promises).spread(function(result1, result2, result3) { 
    console.log(result1, result2, result3); 
}); 
+0

嘿@Exception,我想告訴你這個工作也是如此。我很難決定將哪個人授予答案。非常感謝你。這非常有用。 – Ciel

+0

@Ciel不介意你接受了誰的回答,只對我而言重要的是我的回答是否有幫助:) – Exception

+0

這確實非常有用。以我在這裏學到的東西,我爲另一個問題提出了一個新的解決方案,你可以在這裏看到答案 - 我已經留下了這個問題,以防有人看到它,並且看到一個更簡單的方法來實現它,但我爲它感到自豪。 。 http://stackoverflow.com/questions/24352165/using-q-js-broken-between-two-files-in-asp-net-mvc – Ciel

1

我最熟悉你提到the async library,所以我會展示如何使用它。參考其他答案Q.

你的代碼的整體結構是你想要連續做的事情:一個接一個。所以:

async.series([ 
    function(callback) { 
     // do something 
    }, 
    function(callback) { 
     // do something else 
    }, 
    function(callback) { 
     // and something else still 
    } 
], function(err) { 
    // if err is set, an error occurred somewhere in the series 
    // otherwise, all the above functions completed 
}); 

這樣就會是整體結構。那麼,那個加載每個文件的東西呢?從本質上講,你想從文件名映射到文件內容,並async可以很容易地異步映射:

async.map(files, function(file, callback) { 
    jQuery.ajax({ 
     url: file, 
     success: function(data) { return callback(null, data); }, 
     failure: function(err) { return callback(err);  } 
    }); 
}, function(err, fileData) { 
    // if err is set, an error occurred while fetching one of the files 
    // otherwise, fileData is an array with the file data 
}); 

你可以,當然,巢狀async.map調用內部的任何傳遞給async.series的功能,那就是你如何編寫小部分,直到完成整個工作流程。

+0

這真的很棒,'async'庫看起來非常酷。它是否涉及「可延遲」等?或者'async'被設計用於不同的原理,比如'jsdeferred'?我已經瀏覽了該網站,但我很想聽到圖書館的真正用戶的第一手資料。 – Ciel

+0

@Ciel:它不適用於承諾,不。傳統上使用JavaScript,你只需調用一個函數,然後給它傳遞一個回調函數,當它完成時調用它。承諾是一個更新的發明,即「未來結果」的重新表達,然後可以返回並通過等等。 'async'庫被設計用於傳統的回調風格,而Q則被設計用於加強承諾。由於大多數東西仍然使用回調風格,我發現'async'更方便,並且(不管它是否基於事實),它只是感覺更輕量級。 – icktoofay

+0

@Ciel:這兩種風格當然可以互操作:你可以在承諾上調用'then',傳遞一個回調,使用promise類型的代碼來促進回調式代碼,Q提供了將回調式函數包裝爲promise風格的功能。 – icktoofay