Promise可以按顺序加载多个URL吗?

let*_*ian 1 javascript promise

然后返回指定的Promise给出以下代码段:

function get(url) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);
      }
      else {
        reject(Error(req.statusText));
      }
    };
    req.onerror = function() {
      reject(Error("Network Error"));
    };
    req.send();
  });
}
Run Code Online (Sandbox Code Playgroud)

该功能可以如下使用:

get('story.json').then(function(response) {
  console.log("Success!", response);
}, function(error) {
  console.error("Failed!", error);
});
Run Code Online (Sandbox Code Playgroud)

我想使用Promise来加载多个网址,例如

get('a.json').get('b.json')
// or get('a.json').then().get('b.json')
Run Code Online (Sandbox Code Playgroud)

我已经以其他方式实现了它。但是据我了解,Promise无法完成这项工作。真的吗

实际上,我实现了一个类似的库,可帮助在浏览器中执行动态脚本:

Loader = (function() {

  var load_cursor = 0;
  var load_queue;

  var loadFinished = function() {
    load_cursor ++;
    if (load_cursor < load_queue.length) {
      loadScript();
    }
  }

  function loadError (oError) {
    console.error("The script " + oError.target.src + " is not accessible.");
  }


  var loadScript = function() {
    var url = load_queue[load_cursor];
    var script = document.createElement('script');
    script.type = "text/javascript";

    if (script.readyState){  //IE
        script.onreadystatechange = function(){
            if (script.readyState == "loaded" ||
                    script.readyState == "complete"){
                script.onreadystatechange = null;
                loadFinished();
            }
        };
    } else {  //Others
        script.onload = function(){
            loadFinished();
        };
    }

    script.onerror = loadError;

    script.src = url+'?'+'time='+Date.parse(new Date());
    document.body.appendChild(script);
  };

  var loadMultiScript = function(url_array) {
    load_cursor = 0;
    load_queue = url_array;
    loadScript();
  }

  return {
    load: loadMultiScript,
  };

})();  // end Loader


// load...

Loader.load(['http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js', './my.js']);
Run Code Online (Sandbox Code Playgroud)

jfr*_*d00 5

使用普通的承诺语法

连锁承诺

如果您希望它们是连续的,则可以将它们链接在一起:

get('a.json').then(function(a) {
    return get('b.json');
}).then(function(b){
    return get('c.json');
}).then(function(c) {
    // all done here
}), function(err) {
    // error here
});
Run Code Online (Sandbox Code Playgroud)

或者在ES7中,您可以这样使用async/await

async function someFunction() {
    let a = await get('a.json');
    let b = await get('b.json');
    // do something with a and b here
    return something;
}

someFunction().then(result => {
    // all done here
}).catch(err => {
    // error here
});
Run Code Online (Sandbox Code Playgroud)

并行运行承诺

如果要并行加载它们,可以使用Promise.all()

Promise.all([get('a.json'), get('b.json'), get('c.json')]).then(function(results) {
    // all done with results here
}, function(err) {
    // error here
});
Run Code Online (Sandbox Code Playgroud)

使用.reduce()的序列

或者,如果您使用相同的代码来处理每个结果,则可以使用reduce()设计模式依次加载它们:

['a.json', 'b.json', 'c.json'].reduce(function(p, item) {
    return p.then(function(){
        // process item here
    });
}, Promise.resolve()).then(function(result) {
    // all done here
}, function(err) {
    // error here
});
Run Code Online (Sandbox Code Playgroud)

使用Bluebird的.map()进行序列

或者,如果使用Bluebird Promise库,它具有Promise.map()对数组上的并行操作非常有用的

Promise.map(['a.json', 'b.json', 'c.json'], function(item) {
    // do some operation on item and return data or a promise
    return something;
}).then(function(results) {
    // all done
}, function(err) {
    // error here
});
Run Code Online (Sandbox Code Playgroud)

制作get(x).get(y).get(z)工作

扩大承诺

我对get(x).get(y).get(z)使用诺言的问题很感兴趣。我在以下工作片段中想到了一种方法:

get('a.json').then(function(a) {
    return get('b.json');
}).then(function(b){
    return get('c.json');
}).then(function(c) {
    // all done here
}), function(err) {
    // error here
});
Run Code Online (Sandbox Code Playgroud)

这有点hack。我认为标准组织正在以一种更正式的方式来扩展这样的承诺,这种承诺在更多情况下将比现在更有效。但是,我在带有Bluebird的Chrome,Firefox和IE中进行了尝试,这种特殊用法在所有这三种方法中均有效。这种方法的挑战在于,每个方法都会.then()创建一个新的Promise,并且默认情况下,它不会包含您的.get()方法。由于它的使用方式,我们在这里不再赘述,但是您必须完全小心使用它。

链接我们自己的对象

这是get(x).get(y).get(z)语法的一些不同方式。它.get()的末尾需要有一个空白,以告诉您它想要停止该链并获得最终的保证。这种方案的优点是它不会以任何方式与promise对象混淆。

async function someFunction() {
    let a = await get('a.json');
    let b = await get('b.json');
    // do something with a and b here
    return something;
}

someFunction().then(result => {
    // all done here
}).catch(err => {
    // error here
});
Run Code Online (Sandbox Code Playgroud)