2017-05-16 22 views
0

我正在努力使一组承诺数组工作。这背后的想法是:执行承诺数组的数组并在每个序列之后依次运行验证回调

附表是以下对象的数组:

[ 
    { priority: 0, actions: [Promise, Promise, Promise, ...] }, 
    { priority: 1, actions: [Promise, Promise, Promise, ...] } 
    ... 
] 

的承诺是AJAX调用(在我的例子,我用随机超时后解决假货的承诺嘲笑他们) 。

时间表然后按优先级排序并执行其操作。在下一系列操作的验证回调后,只应运行之后全部回调为当前系列返回true。如果任何Promise被拒绝或者结果验证失败,则应停止执行。换句话说,我需要它在以下情况下工作:

  1. progressBar.activate() - 蓝色。
  2. 所有系列的所有承诺都是异步启动的。
  3. 当优先级0 Promise的结果到达时,以异步方式验证它们。不要验证以下系列的结果。
    • 任何验证失败?任何优先级0的承诺都会被拒绝?
      • YES:progressBar.error() - 红色;立即返回。
    • ALL验证优先级为0承诺是好的?
      • 是:转到下一步。
  4. 验证结果优先级1分的承诺。
    • ...
    • ...
  5. 验证结果优先级2分的承诺。
    • ...
    • ...
  6. 全部完成,progressBar.deactivate() - 橙色。

但我不能让它按顺序运行 - 从所有系列中的结果到达时生效,按随机顺序!我想我不能在我的syncRun()方法中正确链接电话。在进程完成之前progressBar也被异步禁用:

var syncRun = function (schedule) { 
    var tasks = sortSchedule(schedule); 
    progressBar.activate(); 
    var chain = $.Deferred().resolve(); 
    tasks.forEach(function (step) { 
     // increase the total empty width of progressBar 
     progressBar.totalProgress += step.length; 
     // chain the next series of promises 
     chain = chain.then(function() { 
       return Promise.all(step); 
      } 
     ); 
    }); 
    // chain the final action: deactivate progressBar 
    chain = chain.then(function() { 
     progressBar.deactivate(); 
    }, function() {}); 
}; 

任何建议表示赞赏。下面是完整的代码:

var progressBar = { 
 
    activate: function() { 
 
    $('#progress-bar').addClass('active'); 
 
    }, 
 
    deactivate: function() { 
 
    $('#progress-bar').removeClass('active'); 
 
    }, 
 
    error: function() { 
 
    $('#progress-bar').addClass('error'); 
 
    }, 
 
    current: 0, 
 
    total: 0, 
 
    setWidth: function() { 
 
    var widthPercent = 0; 
 
    if (this.total !== 0) { 
 
     widthPercent = this.current/this.total * 100 + '%'; 
 
    } 
 
    $('#progress-bar').css('width', widthPercent); 
 
    }, 
 
    get totalProgress() { 
 
    return this.total; 
 
    }, 
 
    set totalProgress(value) { 
 
    this.total = value; 
 
    this.setWidth(); 
 
    }, 
 
    get currentProgress() { 
 
    return this.current; 
 
    }, 
 
    set currentProgress(value) { 
 
    this.current = value; 
 
    this.setWidth(); 
 
    } 
 
}; 
 

 
var logger = function(message) { 
 
    $('<p></p>').text(message).appendTo($('#logger')); 
 
}; 
 

 
var resolveLimit = 6; 
 
var validatorLimit = 6; 
 

 
var fakeAjax = function(id) { 
 
    return new Promise(function(resolve, reject) { 
 
    setTimeout(function() { 
 
     if (id <= resolveLimit) { 
 
     resolve(id); 
 
     } else { 
 
     reject(id); 
 
     } 
 
    }, (Math.random() * 5 | 0) * 1000); 
 
    }); 
 
}; 
 

 
var action = function(request, callback) { 
 
    request.then(function(result) { 
 
    progressBar.currentProgress++; 
 
    var isValid = callback(result); 
 
    if (!isValid) { 
 
     throw 'Rejected ' + result; 
 
    } 
 
    }); 
 
}; 
 

 
var validator = function(result) { 
 
    if (result <= validatorLimit) { 
 
    logger('Series #' + result + ' parsed'); 
 
    return true; 
 
    } else { 
 
    logger('Series #' + result + ' rejected'); 
 
    progressBar.error(); 
 
    return false; 
 
    } 
 
}; 
 

 
// Generate an array of action objects of specified length 
 
var guid = 0; 
 
var generateActions = function(count) { 
 
    var result = []; 
 
    for (var i = 0; i < count; i++) { 
 
    result.push(
 
     action(fakeAjax(guid), validator) 
 
    ); 
 
    } 
 
    guid++; 
 
    return result; 
 
}; 
 

 

 
var sortSchedule = function(schedule) { 
 
    var tasks = []; 
 
    schedule.forEach(function(step) { 
 
    if (!tasks[step.priority]) { 
 
     tasks[step.priority] = []; 
 
    } 
 
    tasks[step.priority] = tasks[step.priority].concat(step.actions); 
 
    }); 
 
    return tasks.sort(function(a, b) { 
 
    return tasks[b] - tasks[a]; 
 
    }); 
 
}; 
 

 
var syncRun = function(schedule) { 
 
    var tasks = sortSchedule(schedule); 
 
    progressBar.activate(); 
 
    var chain = $.Deferred().resolve(); 
 
    tasks.forEach(function(step) { 
 
    // increase the total empty width of progressBar 
 
    progressBar.totalProgress += step.length; 
 
    // chain the next series of promises 
 
    chain = chain.then(function() { 
 
     return Promise.all(step); 
 
    }); 
 
    }); 
 
    // chain the final action: deactivate progressBar 
 
    chain = chain.then(function() { 
 
    progressBar.deactivate(); 
 
    }, function() {}); 
 
}; 
 

 
var schedule = [{ 
 
    priority: 0, 
 
    actions: generateActions(6) 
 
    }, 
 
    { 
 
    priority: 1, 
 
    actions: generateActions(5) 
 
    }, 
 
    { 
 
    priority: 2, 
 
    actions: generateActions(4) 
 
    }, 
 
    { 
 
    priority: 3, 
 
    actions: generateActions(3) 
 
    }, 
 
    { 
 
    priority: 4, 
 
    actions: generateActions(2) 
 
    }, 
 
    { 
 
    priority: 5, 
 
    actions: generateActions(1) 
 
    } 
 
]; 
 

 
syncRun(schedule);
.progress-bar-container { 
 
    border: #999999 1px solid; 
 
    width: 90%; 
 
    padding: 5px; 
 
    margin-bottom: 10px; 
 
} 
 

 
@keyframes blinker { 
 
    50% { 
 
    opacity: 0.5; 
 
    } 
 
} 
 

 
.progress-bar { 
 
    background-color: #FF9933; 
 
    height: 4px; 
 
    animation: blinker 1s linear infinite; 
 
    width: 100%; 
 
} 
 

 
.active { 
 
    background-color: #0099FF; 
 
} 
 

 
.error { 
 
    background-color: #FF0000 !important; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div class="progress-bar-container"> 
 
    <div id="progress-bar" class="progress-bar"></div> 
 
</div> 
 
<div id="logger"> 
 
</div>

+0

看来,你是在同一时间开始你的所有异步操作,使他们都跑并行并因此以随机顺序完成。如果您希望优先级1操作在优先级0操作完成之前不启动,那么您不需要立即开始优先级1操作,而是等待优先级0承诺数组的“Promise.all()”已经解决。 – jfriend00

+0

承诺是_value_不是行为 - 您需要使用返回承诺而不仅仅是承诺的函数。 –

+0

为什么使用'$ .Deferred'?考虑到你在代码的其他地方使用它,为什么不使用常规的'Promise'呢? –

回答

0

好了,所以我不能完全肯定了,如果这是一个很好的解决方案,但如果任何值可以从它衍生的,我扔在一起类,它承诺在构造函数中,当强制承诺的序列上的每一个决议,等待最终返回积累的结果之前:

class ChainRequest { 
    constructor(promise) { 
    this.promise = promise; 
    this.nextPromise = null; 
    } 

    appendNextPromise (nextPromise) { 
    this.nextPromise = nextPromise; 
    } 

    execute (prevResults) { 
    this.results = prevResults; 
    return this.promise() 
    .then(result => { 
     this.results.push(result); 
     if (this.nextPromise !== null) { 
     return this.nextPromise.execute(this.results); 
     } 
     else { 
     return Promise.resolve(this.results); 
     } 
    }); 
    } 
} 

let chainPromises = [promise1, promise2, promise3...]; 

let currentPromise = new ChainRequest(promise1); 
let headPromise = currentPromise; 

for (let i = 1; i < chainPromises.length; i++) { 
    let nextPromise = new ChainRequest(chainPromises[i)); 
    currentPromise.appendNextPromise(nextPromise); 
    currentPromise = nextPromise; 
} 

return headPromise 
.then(results => { 
    console.log(results); 
}); 
0

首先,改变你的日程安排,以便它列出了行动,而不是立即调用它们:

var schedule = [{ 
    priority: 0, 
    actions: 6 // instead of generateActions(6) 
    }, 
    { 
    priority: 1, 
    actions: 5 
    }, 
    { 
    priority: 2, 
    actions: 4 
    }, 
    { 
    priority: 3, 
    actions: 3 
    }, 
    { 
    priority: 4, 
    actions: 2 
    }, 
    { 
    priority: 5, 
    actions: 1 
    } 
]; 

然后调用它们,你真的想这样做:

var chain = Promise.resolve(); // <- No need to use $.Deferred here 
tasks.forEach(function(stepLength) { 
    // increase the total empty width of progressBar 
    progressBar.totalProgress += stepLength; 
    // chain the next series of promises 
    chain = chain.then(function() { 
    return Promise.all(generateActions(stepLength)); 
    }); 
});