0
在JavaScript中,我怎樣才能最好地將多個值作爲參數獲取到回調函數中,最好不添加庫依賴項?如何使用多個XMLHttpRequest.responseText值?
E.g.考慮
function eventHandler() {
getSomethingAsync(function(something){
getOtherAsync(function(other){
console.log([something.value, other.status]);
});
});
}
這看起來像CallbackHell(.com)的起點。
在其他一些語言我想在這一點上使用的承諾,沿
function eventHandler() {
var something = getSomethingPromise();
var other = getOtherPromise();
console.log([something.get().value, other.get().status]);
}
行,但似乎連ES6-的承諾不甚允許代碼這樣的通貨緊縮,詳細保留(錯誤易發?)的重複圖案像
Promise.all([somePromise, otherPromise]).then(
function([some, other]){
console.log([some.value, other.status]);
});
我跑進試圖通過提供chrome.tabs.getSelected
的標籤結合的例子,並通過XMLHTTPRequest
在Chrome擴展提供的responseText
(參見「實施例編號#2」下面)。
示例代碼#1(實體模型)
複製/粘貼到顯影劑控制檯stackoverflow.com原點內。
從不同(模型)異步函數中獲取三個值,並從中構造一個新對象。出於演示目的,結果將簡單地打印到控制檯。
// mockup async functions
function someAsyncAPI(){
var handle = { 'send': function(){ handle.callback({value: 'SOME_VALUE'}); }}
return handle;
}
function otherAsyncAPI(callback){
callback({ 'version': '1.0', 'value': 'OTHER_VALUE' });
}
function callbackHell(){
// Issue:
// - One level of nesting for each value.
// - Hard to add more values.
// - Doesn't make use of irrelevance of order of evaluation.
var req = new XMLHttpRequest();
req.open('GET', '/jobs');
req.onload = function(){
var handle = someAsyncAPI();
handle.callback = function(someValue){
otherAsyncAPI(function(otherValue){
console.log({
mode: 'direct-callback',
jobs: req.responseText,
some: someValue.value,
other: otherValue.value});
});
};
handle.send();
};
req.send();
}
function promiseVersion(){
// Issue:
// - Still seems repetitive, verbose.
// - Promise.all line repeats variable names (likely place of errors?).
var jobsPromise = new Promise(function(resolve,reject){
var req = new XMLHttpRequest();
req.open('GET', '/jobs');
req.onload = function() { resolve(req.responseText); };
req.send();
});
var somePromise = new Promise(function(resolve,reject){
var handle = someAsyncAPI();
handle.callback = resolve;
handle.send();
});
var otherPromise = new Promise(function(resolve,reject){
otherAsyncAPI(resolve);
});
Promise.all([jobsPromise, somePromise, otherPromise])
.then(function([jobsValue, someValue, otherValue]){
console.log({
mode: 'direct-callback',
jobs: jobsValue,
some: someValue.value,
other: otherValue.value});
});
}
callbackHell();
promiseVersion();
實施例的代碼#2(現實世界中的示例)
Chrome擴展程序,通過重定向到數據URI休眠當前標籤。本質上,我認爲像「TabMemFree」這樣的插件的核心思想。
# --- popup.js -----------------------------------------------------
"use strict";
document.getElementById('hibernateTab1').onclick = hibernateTab1;
document.getElementById('hibernateTab2').onclick = hibernateTab2;
function hibernateTab1(tab){
// Issues:
// - Unintuitive order or statements
// - Beginning of nesting-hell
chrome.tabs.getSelected(null, function(selectedTab){
var req = new XMLHttpRequest();
req.open('GET', 'suspended.html');
req.onload = function(){
var pagesource = req.responseText
.replace(/__TITLE__/g, JSON.stringify(selectedTab.title))
.replace(/__BACKURL__/g, JSON.stringify(selectedTab.url));
var datauri = "data:text/html;base64," + btoa(pagesource);
chrome.tabs.update(selectedTab.id, {"url": datauri});
};
req.send();
});
}
function hibernateTab2(){
// Improvements:
// - Clean separation of independent steps.
// - Reduces nesting by one level per independent asynchronous
// value after the first.
// - Independent values might even be calculated in parallel?
// Issues:
// - Duplicate variable names in `Promise.all` line are prone to error.
// - Still seems needlessly long, with a lot of padding.
var template = new Promise(function(resolve,reject){
var req = new XMLHttpRequest();
req.open('GET', 'suspended.html');
req.onload = function(){ resolve(req.responseText); };
req.send();
});
var selectedTab = new Promise(function(resolve,reject){
chrome.tabs.getSelected(null, resolve);
});
Promise.all([template, selectedTab]).then(function([template, selectedTab]){
var pagesource = template
.replace(/__TITLE__/g, JSON.stringify(selectedTab.title))
.replace(/__BACKURL__/g, JSON.stringify(selectedTab.url));
var datauri = "data:text/html;base64," + btoa(pagesource);
chrome.tabs.update(selectedTab.id, {"url": datauri});
});
}
# --- popup.html -----------------------------------------------------
<html>
<head>
<title>Silence of the Tabs</title>
</head>
<body style='width:300px;'>
<p><h1>Hello World.</h1></p>
<p><a href='#' id='hibernateTab1'>hibernateTab1()</a></p>
<p><a href='#' id='hibernateTab2'>hibernateTab2()</a></p>
</body>
<script src='popup.js'></script>
</html>
# --- suspended.html -----------------------------------------------------
<html>
<body>
<a id='goback'>Go Back</a>
</body>
<script>
var g = document.getElementById('goback');
var url=__BACKURL__;
var title=__TITLE__;
document.title=title;
g.href = 'javascript:goback()';
g.innerText = title;
function goback(){
if(history.length > 2){
history.back();
} else {
location.href = url;
}
}
</script>
</html>
# --- manifest.json -----------------------------------------------------
{
"manifest_version": 2,
"name": "Unload Tab",
"description": "Unload Tab",
"version": "0.1",
"browser_action": {
"default_popup": "popup.html"
},
"permissions": [
"activeTab"
]
}
這有什麼錯'Promise.all()'? – SLaks
看看'fetch' API。 – Ginden
[將一個Deferreds數組傳遞給$ .when()](https://stackoverflow.com/questions/5627284/pass-in-an-array-of-deferreds-to-when) – vinayakj