如何使用多个XMLHttpRequest.responseText值? [英] How to use multiple XMLHttpRequest.responseText values?

查看:62
本文介绍了如何使用多个XMLHttpRequest.responseText值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆