2012-07-12 64 views
1

介紹鏈接多個異步功能

我有一個問題來自這一個來:

Loop calling an asynchronous function

一旦我得到了一個循環調用使用承諾狀圖案異步函數(jsdeferred使用SDK開發的附加組件庫)。

var sess = ...; 
Deferred.define(this);  
function asyncFunction (session) { 
    Deferred.next(function() { 
     var d = new Deferred(); 
     (new Request({ 
       url: form.php, 
       content: "sess=" + session, 
       onComplete: function (response) { 
        d.call(response.json); 
       } 
     })).get(); 
     return d; 
    }).next(function(resp) { 
     if (resp.id) { 
      asyncFunction(session); 
      console.log(resp.msg);    
     }   
    }); 
} 

asyncFunction(sess); 

我想鏈新asynchrnous功能到這個請求,例如,打開瀏覽器的標籤:我不想繼續執行,直到已準備就緒。

問題

所以我得到這樣的:

var sess = ...; 
Deferred.define(this);  
function asyncFunction (session) { 
    Deferred.next(function() { 
     var d = new Deferred(); 
     (new Request({ 
       url: form.php, 
       content: "sess=" + session, 
       onComplete: function (response) { 
        d.call(response.json); 
       } 
     })).get(); 
     return d; 
    }) 
    .next(function(resp) { 
     var d = new Deferred(); 
     // Load tab 
     tabs.activeTab.url = 'http://foo.com'; 
     tabs.activeTab.on('ready', function() { 
      console.log(resp.id); 
      d.call(resp.id); 
     }); 
     return d; 
    }) 
    .next(function(resp) { 
     if (resp.id) { 
      asyncFunction(session); 
      console.log(resp.msg);    
     }   
    }); 
} 

asyncFunction(sess); 

而我得到的是,對於循環的每個迭代,它再次運行所有先前請求的結果!所以,我得到了下面的日誌中我的控制檯:

id1 
msg1 
id1 
msg1 
id2 
msg2 
id1 
msg1 
id2 
msg2 
id3 
msg3 
... 

顯然,我的預期是:

id1 
msg1 
id2 
msg2 
id3 
msg3 

問題

很清澈,我不明白的承諾的模式。我在兩個API讀了很多:

首先是我一直使用到現在爲止的一個。當我嘗試要求庫中的第二個給出了一個錯誤:

const { defer } = require('api-utils/promise'); (+) 

所以,我的問題是,如果你知道承諾的任何好的教程或一些很好的例子約鏈接多個異步函數。或者如果你知道如何去做,你會怎麼做。

謝謝

編輯:給予行(+)

error: An exception occurred. 
Traceback (most recent call last): 
    File "resource://ares-at-iiia-dot-csic/api-utils/lib/promise.js", line 16, in 
    }.call(this, function(require, exports) { 
    File "resource://ares-at-iiia-dot-csic/api-utils/lib/promise.js", line 6, in return  function promised 
    if (typeof(define) === 'function') { // RequireJS 
    File "function promisedConcat(promises, unknown) {return promises.then(function   (values) {return resolve(unknown).then(function (valu 
e) {return values.concat(value);});});", line NaN, in function promisedConcat 
    File "function execute(args) {return call.apply(call, args);", line NaN, in function  execute 
    File "exports.reject = reject;var promised = function() {var call =  Function.call;var concat = Array.prototype.concat", line NaN, in 
exports.reject = reject;var promised = function 
    File "function reject(reason, prototype) {var deferred =   defer(prototype);deferred.reject(reason);return deferred.promise;", line NaN 
, in function reject 
    File "exports.resolve = resolve", line NaN, in exports.resolve = resolve 
    File "function resolve(value, prototype) {var deferred =  defer(prototype);deferred.resolve(value);return deferred.promise;", line NaN 
, in function resolve 
    File "exports.defer = defer", line NaN, in exports.defer = defer 
    File "if (pending) {pending.push([resolved, rejected]);} else {result.then(resolved,  rejected);}return deferred.promise;}}});var defe 
rred = {promise: promise, resolve: function resolve(value) {if (pending) {result =  isPromise(value) ? value : resolution(value);while (
pending.length) {result.then.apply(result, pending.shift());}pending = null;}},  reject", line NaN, in if 
    File "function rejected(reason) {deferred.resolve(reject(reason));", line NaN, in  function rejected 
    File "function resolved(value) {deferred.resolve(resolve(value));", line NaN, in  function resolved 
    File "function defer(prototype) {var pending = [], result;prototype = prototype ||  prototype === null ? prototype : Object.prototype; 
var promise = Object.create(prototype, {then: {value: function then(resolve, reject)  {var deferred = defer(prototype);resolve = resolve 
? attempt(resolve) : resolution;reject = reject ? attempt(reject) ", line NaN, in  function defer 
    File "function isPromise(value) {return value && typeof value.then === "function";",  line NaN, in function isPromise 
    File "function attempt(f) {return function effort(options) {try {return f(options);}  catch (error) {return rejection(error);}};", lin 
e NaN, in function attempt 
    File "function rejection(reason) {return {then", line NaN, in function rejection 
    File "function resolution(value) {return {then", line NaN, in function resolution 
    File "((function (require, exports) {"use strict"", line NaN, in 
    File "resource://ares-at-iiia-dot-csic/api-utils/lib/globals!.js", line 75, in getter 
    value: define.bind(this) 
TypeError: can't redefine non-configurable property 'define' 
+0

是您的加載項SDK版本目前? 'promise'模塊已添加到Add-on SDK 1.7中。 – 2012-07-12 12:39:41

+0

是的,我有1.8版本。我在api-utils文件夾中找到了該庫。我將編輯以發佈錯誤。 – synack 2012-07-13 07:10:26

回答

2

嗯,看起來有點像一個範圍問題的錯誤。在你的最後一個函數中,應該沒有可用的變量resp - 我不確定它的真實記錄。

是的,因爲你最後再次調用asyncFunction,只要響應中有一個id,你可能會得到一個無限循環。

但是,讓我們嘗試使用add-on sdk's promises(不,我從來沒有使用過 - 但它說,它是基於CommonJS Promises/A):

const { defer } = require('api-utils/promise'); 
// or whatever you need in your code to use them - I'm no addOn-developer 

var sess = ...; 
Deferred.define(this);  
function asyncFunction (session) { 
/* returns a promise itself */ 

    var d = defer(); 
    (new Request({ 
     url: form.php, 
     content: "sess=" + session, 
     onComplete: function (response) { 
      d.resolve(response.json); 
     } 
    })).get(); 
    return d.promise.then(function(resp) { 
     var d = defer(); 
     // Load tab 
     tabs.activeTab.url = 'http://foo.com'; 
     tabs.activeTab.on('ready', function() { 
      d.resolve(resp); 
     }); 
     return d.promise; 
    }).then(function(resp) { 
     console.log("request #"+resp.id+"sucessful: "+resp.msg); 
     if (resp.id) { 
      asyncFunction(session); // call recursively 
     }   
    }); 
} 
asyncFunction(sess); 
+0

你說得對,其實這是實際上看起來我的代碼。當我寫下這個問題時,「def」和「resp」是錯誤的,對不起。您編寫的代碼可以顯示相同的結果,重複以前的迭代。在我看來,使'tab.activeTab.url ='http:// foo.com''觸發先前迭代的處理程序。那可能嗎? – synack 2012-07-12 12:12:38

+1

恩,是的。 「準備好」事件是否會多次觸發?它看起來像這個承諾庫確實允許多次調用「延遲」 - 通常延遲只能一次完成或失敗。 – Bergi 2012-07-12 12:16:04

+0

是的,每次執行'tabs.activeTab.url ='http://foo.com';'時都會觸發它。 @Bergi:你知道如何使用我在這個問題中發佈的附加SDK的承諾庫嗎? – synack 2012-07-12 12:24:14