如何使用多个XMLHttpRequest.responseText值? [英] How to use multiple XMLHttpRequest.responseText values?
问题描述
在javascript中,如何最好地组合仅作为回调函数的参数而获得的多个值,最好不添加库依赖项?
例如。考虑
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提供的选项卡。在Chrome扩展程序中,由
和 XMLHTTPRequest
提供的tabs.getSelected responseText
下面的示例代码2)。
示例代码#1(模型)
将其复制/粘贴到stackoverflow.com原始位置的开发者控制台中。 / p>
从不同的(模型)异步函数中获取三个值,并从它们中构造一个新对象。出于演示目的,仅将结果打印到控制台。
//原型异步函数
函数someAsyncAPI() {
var handle = {'send':function(){handle.callback({value:'SOME_VALUE'});; }}
返回句柄;
}
函数otherAsyncAPI(callback){
callback({’version’: 1.0, value: OTHER_VALUE});
}
函数callbackHell(){
//问题:
//-每个值嵌套一层。
//-难以添加更多值。
//-不利用评估顺序的无关性。
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,
一些:someValue.value,
其他:otherValue.value});
});
};
handle.send();
};
req.send();
}
函数promiseVersion(){
//问题:
//-似乎仍然是重复的,冗长的。
// // Promise.all行重复变量名(可能是错误的地方?)。
var jobsPromise =新的Promise(function(resolve,reject){
var req = new XMLHttpRequest();
req.open('GET','/ jobs');
req.onload = function(){resolve(req.responseText);};
req.send();
});
var somePromise =新的Promise(function(resolve,reject){
var handle = someAsyncAPI();
handle.callback = resolve;
handle.send();
});
var otherPromise =新的Promise(function(resolve,reject){
otherAsyncAPI(resolve);
});
Promise.all([jobsPromise,somePromise,otherPromise])
.then(function([jobsValue,someValue,otherValue]){
console.log({
模式:'直接回调,
个工作:jobsValue,
一些:someValue.value,
其他:otherValue.value});
});
}
callbackHell();
promiseVersion();
示例代码2(实际示例)
Chrome扩展程序,通过重定向到数据URI休眠当前选项卡。从本质上讲,我是对诸如 TabMemFree之类的插件的核心概念的看法。
#--- popup.js ----- ------------------------------------------------
使用严格;
document.getElementById('hibernateTab1')。onclick = hibernateTab1;
document.getElementById('hibernateTab2')。onclick = hibernateTab2;
函数hibernateTab1(tab){
//问题:
//-不直观的命令或语句
//-嵌套地狱
$的开始b $ b 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();
});
}
函数hibernateTab2(){
//改进:
//-独立步骤的清晰分离。
// /-将嵌套后的每个独立异步
//值减少一层。
//-甚至可以并行计算独立值?
//问题:
//-Promise.all行中重复的变量名容易出错。
///-看起来似乎仍然多余,填充很多。
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 =新的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( selectedb.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>标签的静音< / title>
< / head>
< body style =’width:300px;’>
< h1> / 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 =标题;
函数goback(){
if(history.length> 2){
history.back();
}否则{
location.href = url;
}
}
< / script>
< / html>
#-manifest.json ------------------------------- ----------------------
{
manifest_version:2,2,
name: 卸载标签,
描述:卸载标签,
版本: 0.1,
浏览器动作:{
default_popup: popup.html
},
权限:[
activeTab
]
}
显然,异步/等待关键字是我想要的。有了这些,我的样机示例可以写成
async函数async_await_2(){
var jobs = new Promise(function (resolve,reject){
var req = new XMLHttpRequest();
req.open('GET','/ jobs');
req.onload = function(){resolve( req.responseText);};
req.send();
});
var some = new Promise(function(resolve,reject){
var handle = someAsyncAPI();
handle.callback = resolve;
handle.send();
});
var other = new Promise(function(resolve,reject){
otherAsyncAPI(resolve);
});
console.log({
模式:'async-await',
工作:await jobs,
some:(await some).value,
other:(等待other).value});
}
或(可能导致顺序执行而不是并行执行promise)
异步函数async_await(){
//简洁,但是牺牲了Promises的并行性吗?
var jobs =等待新的Promise(function(resolve,reject){
var req = new XMLHttpRequest();
req.open('GET','/ jobs');
req.onload = function(){resolve(req.responseText);};
req.send();
});
var some =等待新的Promise(function(resolve,reject){
var handle = someAsyncAPI();
handle.callback = resolve;
handle.send();
});
var other =等待新的Promise(function(resolve,reject){
otherAsyncAPI(resolve);
});
console.log({
模式: async-await,
个工作:工作,
个:一些值,
个其他:other.value}) ;
}
In javascript, how can I best combine multiple values which are obtained as arguments to callback functions only, preferably without adding library dependencies?
E.g. consider
function eventHandler() {
getSomethingAsync(function(something){
getOtherAsync(function(other){
console.log([something.value, other.status]);
});
});
}
This looks like the starting point of CallbackHell(.com).
In some other languages I would use promises at this point, along the lines of
function eventHandler() {
var something = getSomethingPromise();
var other = getOtherPromise();
console.log([something.get().value, other.get().status]);
}
but it seems that even ES6-promises don't quite allow such deflation of the code, preserving verbose (error-prone?) repetition-patterns like
Promise.all([somePromise, otherPromise]).then(
function([some, other]){
console.log([some.value, other.status]);
});
An example I ran into was trying to combine the tab provided by chrome.tabs.getSelected
and the responseText
provided by an XMLHTTPRequest
in a Chrome extension (see "Example Code #2" below).
Example code #1 (mockup)
Copy/paste into developer console within stackoverflow.com origin.
Obtains three values from different (mockup) async functions, and constructs a new object from them. For demonstration purposes, the result is simply printed to the console.
// 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();
Example code #2 (Real-world example)
Chrome extension that hibernates the current tab by redirecting to a data URI. Essentially my take on the core idea of addons like "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"
]
}
Apparently the async/wait keywords are what I was looking for. With these my mockup example can be written as
async function async_await_2(){
var jobs = new Promise(function(resolve,reject){
var req = new XMLHttpRequest();
req.open('GET', '/jobs');
req.onload = function() { resolve(req.responseText); };
req.send();
});
var some = new Promise(function(resolve,reject){
var handle = someAsyncAPI();
handle.callback = resolve;
handle.send();
});
var other = new Promise(function(resolve,reject){
otherAsyncAPI(resolve);
});
console.log({
mode: 'async-await',
jobs: await jobs,
some: (await some).value,
other: (await other).value});
}
or alternatively (might cause sequential instead of parallel execution of the promises)
async function async_await(){
// Concise, but sacrifices parallelism of the Promises?
var jobs = await new Promise(function(resolve,reject){
var req = new XMLHttpRequest();
req.open('GET', '/jobs');
req.onload = function() { resolve(req.responseText); };
req.send();
});
var some = await new Promise(function(resolve,reject){
var handle = someAsyncAPI();
handle.callback = resolve;
handle.send();
});
var other = await new Promise(function(resolve,reject){
otherAsyncAPI(resolve);
});
console.log({
mode: 'async-await',
jobs: jobs,
some: some.value,
other: other.value});
}
这篇关于如何使用多个XMLHttpRequest.responseText值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!