2017-07-24 16 views
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" 
    ] 
} 
+0

這有什麼錯'Promise.all()'? – SLaks

+0

看看'fetch' API。 – Ginden

+0

[將一個Deferreds數組傳遞給$ .when()](https://stackoverflow.com/questions/5627284/pass-in-an-array-of-deferreds-to-when) – vinayakj

回答

0

顯然async/wait keywords是我一直在尋找。有了這些我樣機例子可以寫成

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}); 
} 

或交替(可能導致順序,而不是承諾的並行執行)

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}); 
}