2013-06-25 100 views
5

在jQuery中,如果您在ajax回調方法中犯了錯誤,您將收到適當的控制檯錯誤消息和堆棧跟蹤。Dojo - 承諾被吞噬的ReferenceError異常

$.get("https://api.github.com/users/octocat/orgs", function() { 
    var a = FAIL; 
}); 

但是,在使用dojo/request/xhr的dojo中,這些愚蠢的錯誤似乎完全被吞噬了。當我運行這個時,我的控制檯中唯一的東西是「然後」和「永遠」。

require(["dojo/request/xhr" ], function(xhr) { 
    var promise = xhr.get("https://api.github.com/users/octocat/orgs"); 
    promise.then(function(data) { 
     console.log('then'); 
     var a = FAIL; 
     console.log('goodbye'); 
    }, function() { 
     console.log('error'); 
    }); 
    promise.otherwise(function() { 
     console.log('otherwise'); 
    }); 
    promise.always(function() { 
     console.log('always'); 
    }); 
}); 

使用棄用的dojo.xhrGet,問題稍微改善。我得到一個控制檯錯誤消息和我的錯誤處理程序的調用,但它只是說「的ReferenceError {}」,併爲我提供了,從來沒有指向我自己的功能堆棧跟蹤:

dojo.xhrGet({ 
    url: "https://api.github.com/users/octocat/orgs", 
    load: function() { 
     console.log('dojo.xhrGet.load'); 
     var a = FAIL; 

     console.log('goodbye dojo.xhrGet.load'); 
    }, 
    error: function() { 
     console.log('dojo.xhrGet.error'); 
    }, 
    handle: function() { 
     console.log('dojo.xhrGet.handle'); 
    } 
}); 

當編寫一個程序,我們做錯誤,很高興我們有像Chrome開發工具這樣的工具來指出我們的錯誤。當您看到堆棧跟蹤和錯誤消息時,找到錯誤所需的時間顯然比沒有反饋時快得多。我在道場沒有得到任何反饋,我不敢相信這樣一個流行的圖書館可以這樣運作。我究竟做錯了什麼?

回答

4

你從jQuery的遺留的承諾的理解是一個其他人有着根本的不同(檢查承諾/ a +實現)。對於這個答案的其餘部分,我會談論promises/a +標準承諾。 Dojo的Deferred實際上不符合+,但它足夠接近,我在此討論的所有內容同樣適用。

承諾是不可變的,您不能通過調用then來更改承諾狀態。承諾代表最終的價值,通過說「一旦價值準備好,做到這一點」就能夠改變承諾是無稽之談。

那麼,希望這可以解釋爲什麼你的錯誤處理程序沒有被調用,但捕捉錯誤的基本思想仍然是完全可能的。你只需要使用返回值。當您在承諾中致電then時,它會返回一個新的(幾乎總是)不同的承諾。這個新的承諾是非常特殊的,如果原始文件被解析,並且你傳遞的成功處理程序被調用,並且返回一些東西,那麼某些東西將成爲第二個承諾的解析值。同樣,如果錯誤處理程序(在第一個承諾上)被觸發,並且該函數返回某些內容,那麼某件事將是第二個承諾的分辨率值。拋出的錯誤也是如此,它們被傳遞給錯誤處理程序(第二個承諾!)。

因此,這裏是寫在一個更承諾/ A +這樣你的第一個代碼示例:

require(["dojo/request/xhr" ], function(xhr) { 
    var promise = xhr.get("https://api.github.com/users/octocat/orgs"); 
    promise.then(function(data) { 
     console.log('then'); 
     var a = FAIL; 
     console.log('goodbye'); 
    }, function() { 
     console.log('error'); 
    }).then(null, function() { 
     console.log('otherwise'); 
    }); 

    promise.always(function() { 
     console.log('always'); 
    }); 
}); 

我真的不明白你想要的總功能做什麼,所以我不知道在哪裏放置一個。關於調用堆棧的問題,我建議檢查一下Q promise庫,它具有令人難以置信的高級異步調用堆棧支持。

+0

這是對發生了什麼事情的很好解釋。下面是你的代碼的一個小改動,它也提供了堆棧跟蹤:http://jsfiddle.net/5rHM6/不幸的是堆棧跟蹤沒有指向正確的行(它指向console.error行)。所以如果你想知道錯誤,這是正確的答案。如果你想找到錯誤,我傾向於選擇我的答案。但是,如果你確實發現了錯誤,那麼儀器會被壓制,所以你無法得到兩全其美的結果。 –

+0

你是對的,它更像是一個消息傳遞服務(「出現錯誤」),而不是使用堆棧跟蹤的完整錯誤拋出服務。我希望你能看看Q庫,這是我所知道的最好的異步庫,他們肯定會處理這個問題。 –

4

在dojoConfig中設置useDeferredInstrumentation:true。這裏是an example

 <script> 
      var dojoConfig = { 
       useDeferredInstrumentation: true 
      }; 
     </script> 
     <script src="js/lib/dojo/dojo.js.uncompressed.js"></script> 

這樣得出console.error一個相當實用的錯誤消息和堆棧跟蹤輸出:

ReferenceError {} "ReferenceError: FAIL is not defined 
    at http://fiddle.jshell.net/gNdCb/2/show/:25:17 
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14205:21) 
    at signalWaiting (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14196:4) 
    at resolve (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14360:5) 
    at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14249:15) 
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14220:6) 
    at signalWaiting (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14196:4) 
    at resolve (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14360:5) 
    at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14249:15) 
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14226:4) 
    ---------------------------------------- 
    rejected at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14252:15) 
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14223:5) 
    at signalWaiting (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14196:4) 
    at resolve (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14360:5) 
    at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14249:15) 
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14220:6) 
    at signalWaiting (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14196:4) 
    at resolve (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14360:5) 
    at signalDeferred (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14249:15) 
    at signalListener (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14226:4) 
    ---------------------------------------- 
Error 
    at Promise.then.promise.then (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:14420:24) 
    at http://fiddle.jshell.net/gNdCb/2/show/:23:13 
    at runFactory (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:1117:43) 
    at execModule (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:1245:5) 
    at http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:812:7 
    at guardCheckComplete (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:1260:5) 
    at contextRequire (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:811:6) 
    at req (http://ajax.googleapis.com/ajax/libs/dojo/1.9.0/dojo/dojo.js.uncompressed.js:137:11) 
    at http://fiddle.jshell.net/gNdCb/2/show/:21:1" 
+0

當然,能夠在window.onerror之類的東西中實際捕獲或處理這些錯誤將會很好。有什麼建議麼? –

+0

請參閱@David McMullin的答案以接收錯誤 –

0

我有非常特殊的需求,我需要擊中瀏覽器實現的本地catch子句的例外。沒關係,爲什麼我需要這個,但是我用的是這樣的:

function scream(func) { 
    return function() { 
     var args = arguments; 
     setTimeout(function(){ 
      func.apply(null, args); 
     }, 0); 
    }; 
} 

然後,要使用它

var promise = xhr.get("https://api.github.com/users/octocat/orgs"); 
promise.then(scream(function(data) { 
    //do stuff 
})); 

通過使用setTimeout的,你執行功能的瀏覽器事件隊列,使它不可能爲dojo吞下你的例外。但是,一般來說,這是一個不好的解決方案,因爲:

  • 它改變了堆棧跟蹤的一部分
  • 它改變了你的代碼的一部分,其先前執行的同步異步,它可以改變程序的行爲
  • 你不能鏈接多個.then()承諾對象的返回值,這是承諾的真正好事之一。

無論如何,我只是把它作爲選項提出來。