可以承诺按顺序加载多个URL吗? [英] Can Promise load multi urls in order?

查看:79
本文介绍了可以承诺按顺序加载多个URL吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

承诺然后返回指定的承诺提供以下代码段:

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

此功能可用如下:

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

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

I want to use promise to load multi urls, such as

get('a.json').get('b.json')
// or get('a.json').then().get('b.json')

我已经以其他方式实现了它。但据我了解,Promise不能做这项工作。真的吗?

I have implemented it in other ways. But as I understand it, Promise can not do this work. Really ?

事实上,我实现了一个类似的lib,可以帮助在浏览器中执行动态脚本: / p>

In fact, I implemented a similar lib that help execute dynamic scripts in browsers:

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']);


推荐答案

使用正常承诺语法



连锁承诺

如果你想要顺序,你可以将你的承诺链接起来:

You can chain your promises if you want them sequential:

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

或者在ES7中,你可以使用 async / await 像这样:

Or in ES7, you can use async/await like this:

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

并行运行承诺

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

If you want them loaded in parallel, you can use 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
});

序列使用.reduce()

或者,如果使用相同的代码处理每个结果,可以使用 reduce()设计模式按顺序加载它们:

Or, if you use the same code to process each result, you can load them sequentially using the reduce() design pattern:

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

序列使用Bluebird的.map()

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

Or, if using the Bluebird promise library, it has Promise.map() which is very useful for parallel operations on an array

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






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



延长承诺

我对使用promises的 get(x).get(y).get(z)问题很感兴趣。我在这个工作片段中想出了一种方法:

I was intrigued by the get(x).get(y).get(z) question using promises. I conjured up a way to do that in this working snippet:

function get(url) {
    function pget(u) {
        var p = this.then(function (result) {
            log(result);
            return get(u);
        });
        p.get = pget;
        return p;
    }
    var p = new Promise(function (resolve, reject) {
        setTimeout(function() {
            resolve(url);
        }, 500);
    });
    p.get = pget;
    return p;
}

get('a.json').get('b.json').get('c.json').then(function(result) {
    log(result);
    log("done");
}, function(err) {
    log("err");
});

function log(x) {
    var div = document.createElement("div");
    div.innerHTML = x;
    document.body.appendChild(div);
}

这是一个有点黑客。我认为标准组织正在采用一种更为官方的方式来扩展这样的承诺,这种承诺将在更多情况下发挥作用。但是,我在Chrome,Firefox和IE中使用Bluebird进行了尝试,这种特殊用法适用于所有三种。这种方法的挑战是每个 .then()创建一个新的承诺,默认情况下,它不会有你的 .get()方法就可以了。我们在这里因为它的使用方式而侥幸成功,但是你必须要小心使用它。

This is a bit of a hack. I think the standards body is working on a more official way to extend a promise like this that will work in more cases than this will. But, I tried it in Chrome, Firefox and IE with Bluebird and this particular usage works in all three. The challenge with this method is that every .then() creates a new promise and, by default, it will not have your .get() method on it. We get away with it here because of the way it is used, but you would have to be careful exactly how you use this.

链接我们自己的对象

这里有一个不同的方法来做 get(x).get(y).get(z)语法。它最后需要一个空白 .get()来告诉你它想要停止链并获得最终承诺的访问权限。这种方案的优点是它不会以任何方式混淆promise对象。

Here's a bit different way to do the get(x).get(y).get(z) syntax. It requires a blank .get() at the end to tell you it want to stop the chain and get access to the final promise. The advantage of this scheme is that it doesn't mess with the promise object in any way.

function delay(url) {
    return new Promise(function (resolve, reject) {
        setTimeout(function() {
            log(url);
            resolve(url);
        }, 500);
    });
}

function get(url) {
    
    function pget(u) {
        if (!u) {
            return this.promise;
        } else {
            return {promise: this.promise.then(function() {
                return delay(u);
            }), get: pget}
        }
    }
    
    return {promise: delay(url), get: pget};
}

// note the empty .get() right before the .then()
// the empty .get() at the end is required in this scheme
get('a.json').get('b.json').get('c.json').get().then(function(result) {
    log("done");
}, function(err) {
    log("err");
});


function log(x) {
    var div = document.createElement("div");
    div.innerHTML = x;
    document.body.appendChild(div);
}

这篇关于可以承诺按顺序加载多个URL吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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