之前在“foreach”中运行下一次只需在javascript

时间:2016-06-28 20:15:43

标签: javascript foreach promise

这可能很简单,但我找不到办法。 我有一个数组,我想为每个数组值执行一些操作但仅在前一个完成后执行。 让我说我有一个数组[1,2,3,4,5],我想添加一个名为“picture”+ i +“。jpg”的图片的img标签,如果图片文件不存在 - 使用默认图片,用这个img做更多的动作,只有在完成所有操作后,再做一次“foreach”。

我正在研究承诺,但仍然无法弄明白。 问题是它不仅仅是一个异步动作(ajax或get),而是一些不同的动作。

由于

2 个答案:

答案 0 :(得分:0)

不确定这是否是您所需要的。但我确实必须解决几个异步对话框的情况,所以这应该工作。请注意,这需要支持Promise的浏览器或要求您使用Promise垫片。

var items = [1,2,3,4,5];
var chainObj = {}; // Set this up if you need to communicate info to subsequent items. Or you need some form of "reduce" capability.
var promise = Promise.resolve(accumObj); // The initial promise.
for (var i = 0; i < items.length; i++){
    var currItem = items[i];
    promise = promise.then(function(accumObj){
        if (/*Need Async Stuffs*/){
            return new Promise(function(resolve, reject){
                /*perform some async stuff for the currItem. Once they're done, update accumObj and invoke the below function*/
                resolve(accumObj);
            });
        } else {
            /* Perform non-async stuffs for currItem, update accumObj as needed. */
            return accumObj; // Return the accumObj for the next step.
        }
    });
}
promise.then(/*Put call back to finish up anything else that's left*/);

以上将保证每个“项目”在前一项完成之前不会开始处理,只要您在完成所有异步操作后只调用“resolve”(如果需要,在每个循环中将多个promise链接在一起)根据需要)。

简而言之,上面的调用会创建一长串承诺,如下面的伪代码:

Promise.resolve(chainObj)
.then(/*Process items[0]*/)
.then(/*Process items[1]*/)
.then(/*Process items[2]*/)
.then(/*Process items[3]*/)
.then(/*Process items[4]*/)    
.then(/*Process for when everything is done*/)

每个流程步骤要么立即解析(else部分,也称为非异步路径),要么在某些异步操作(/*Need Async stuffs*/路径)后解析。并且后续流程步骤仅在前一流程步骤结算后才会启动。 accumObj允许您累积每个步骤的结果并将其传递给下一步。

代码块中的最后promise.then是您处理完所有内容后可以执行任何最终操作的地方。

CAVEAT:上面的示例代码不处理任何错误/异常。

编辑#1: 要处理相对复杂的操作,请将promise = promise.then...块修改为此。

promise = promise.then(function(accumObj){
            // Start running you async stuffs
            var promises = [];
            promises.push(new Promise(function(resolve, reject){
               // Async function #1. Invoke resolve when the async function completes (simplest solution, pass "resolve" to whatever callback the 
               // The async fucntion uses.
            });
            promises.push(new Promise(function(resolve, reject){ // Async function #2. });
            promises.push(new Promise(function(resolve, reject){ // Async function #3. });
            // ...
            promises.push(new Promise(function(resolve, reject){ // Async function #Last. });

            // Do synchronous function here.
            return Promise.All(promises).then(function(results){
                // Process the results from your async calls, udpate accumObj as needed.
                return accumObj;
            });
        });

以上操作是在处理同步函数之前为当前项启动所有异步函数(让异步并行运行)。 return Promise.All(promises).then(function(results){return accumObj;});返回执行以下操作的另一个承诺。

  1. “等待”(这种情况以异步方式发生),直到promises中的每个承诺都得到解决。
  2. 使用每个承诺中的已解析值数组调用then回调中的函数(results[0]是已解析的值或promises[0],依此类推)。
  3. 该函数返回accumObj,它将成为return Promise.All(promises).then(function(results){return accumObj;});的解析值。

答案 1 :(得分:0)

我最终得到以下代码

$('.imageloaderbutton').on('click', function(){
   var defaultimage='http://mysite/images/none.gif';
   var ds={}; var a=[{'name':'test1'},{'name':'test5'},{'name':'test3'},{'name':'test4'}], i=a.length; 
   var addimagefromarray = function(n){
     console.log('deferring '+n );          ds[n]=$.Deferred();      var imgn=a[n].name
     var $avt=$('<img/>')
      .error(function(){ $(this).attr("src", defaultimage);  })      
      .attr('src', 'http://mysite/images/'+imgn+'.jpg')
      .load(function(){  
            $('.imagesdiv').append($(this)); 
            ds[n].resolve();   
            if(n<(i-1)){ds[n].done(li(n+1));}   
       });
    }
    li(0); 
}); 

但是感谢ShuberFu的答案 - 这非常有用