我正在运行以下形式的事件循环:
var i;
var j = 10;
for (i = 0; i < j; i++) {
asynchronousProcess(callbackFunction() {
alert(i);
});
}
Run Code Online (Sandbox Code Playgroud)
我试图显示一系列显示数字0到10的警报.问题是,当回调函数被触发时,循环已经经历了几次迭代并且它显示了更高的值i.有关如何解决此问题的任何建议?
我刚刚发现,在this.setState()任何组件中的react 函数是异步的,或者在调用它的函数完成后调用.
现在我搜索并找到了这个博客(http://www.bennadel.com/blog/2893-setstate-state-mutation-operation-may-be-synchronous-in-reactjs.htm)
在这里,他发现setState异步(在堆栈为空时调用)或同步(调用后立即调用)取决于触发状态变化的方式.
现在这两件事很难消化
setState函数在函数内部被调用updateState,但触发updateState函数的内容并不是被调用函数所知道的.setState像JS一样异步是单线程语言,这个setState不是WebAPI或服务器调用,所以必须只在JS的线程上完成.他们是这样做的,以便重新渲染不会停止所有事件监听器和东西,或者存在其他一些设计问题.我正在阅读Deferreds and Promises并继续发表$.when.apply($, someArray).我有点不清楚它究竟是做什么的,寻找一条线正确工作的解释(而不是整个代码片段).这是一些背景:
var data = [1,2,3,4]; // the ids coming back from serviceA
var processItemsDeferred = [];
for(var i = 0; i < data.length; i++){
processItemsDeferred.push(processItem(data[i]));
}
$.when.apply($, processItemsDeferred).then(everythingDone);
function processItem(data) {
var dfd = $.Deferred();
console.log('called processItem');
//in the real world, this would probably make an AJAX call.
setTimeout(function() { dfd.resolve() }, 2000);
return dfd.promise();
}
function everythingDone(){
console.log('processed all items');
}
Run Code Online (Sandbox Code Playgroud) 我有一个类似于数组的数组,它暴露了异步方法.async方法调用返回数组结构,进而显示更多异步方法.我正在创建另一个JSON对象来存储从此结构获取的值,因此我需要小心跟踪回调中的引用.
我编写了一个强力解决方案,但我想学习一个更惯用或更干净的解决方案.
这是一些部分代码 -
var jsonItems = [];
items.forEach(function(item){
var jsonItem = {};
jsonItem.name = item.name;
item.getThings().then(function(things){
// or Promise.all(allItemGetThingCalls, function(things){
things.forEach(function(thing, index){
jsonItems[index].thingName = thing.name;
if(thing.type === 'file'){
thing.getFile().then(function(file){ //or promise.all?
jsonItems[index].filesize = file.getSize();
Run Code Online (Sandbox Code Playgroud) // let's say there is a list of 1000+ URLs
string[] urls = { "http://google.com", "http://yahoo.com", ... };
// now let's send HTTP requests to each of these URLs in parallel
urls.AsParallel().ForAll(async (url) => {
var client = new HttpClient();
var html = await client.GetStringAsync(url);
});
Run Code Online (Sandbox Code Playgroud)
这是问题所在,它会同时启动1000多个Web请求.有没有一种简单的方法来限制这些异步http请求的并发数量?这样在任何给定时间都不会下载超过20个网页.如何以最有效的方式做到这一点?
我目前正在尝试使用一些异步方法来创建我的应用程序.我的所有IO都是通过接口的显式实现完成的,我对如何使操作异步感到困惑.
在我看到的情况下,我在实现中有两个选项:
interface IIO
{
void DoOperation();
}
Run Code Online (Sandbox Code Playgroud)
OPTION1: 执行隐式实现异步并等待隐式实现中的结果.
class IOImplementation : IIO
{
async void DoOperation()
{
await Task.Factory.StartNew(() =>
{
//WRITING A FILE OR SOME SUCH THINGAMAGIG
});
}
#region IIO Members
void IIO.DoOperation()
{
DoOperation();
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
选项2: 显式实现异步并等待隐式实现中的任务.
class IOAsyncImplementation : IIO
{
private Task DoOperationAsync()
{
return new Task(() =>
{
//DO ALL THE HEAVY LIFTING!!!
});
}
#region IIOAsync Members
async void IIO.DoOperation()
{
await DoOperationAsync();
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
这些实现中的一个是否比另一个更好,还是有另一种方法可以解决这个问题?
与上面的RulyCanceler类的代码相比,我想使用运行代码 CancellationTokenSource.
如何在取消令牌中提到它,即不抛出/捕获异常?我可以使用该IsCancellationRequested物业吗?
我试图像这样使用它:
cancelToken.ThrowIfCancellationRequested();
Run Code Online (Sandbox Code Playgroud)
和
try
{
new Thread(() => Work(cancelSource.Token)).Start();
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled!");
}
Run Code Online (Sandbox Code Playgroud)
但这cancelToken.ThrowIfCancellationRequested();在方法中给出了运行时错误Work(CancellationToken cancelToken):
System.OperationCanceledException was unhandled
Message=The operation was canceled.
Source=mscorlib
StackTrace:
at System.Threading.CancellationToken.ThrowIfCancellationRequested()
at _7CancellationTokens.Token.Work(CancellationToken cancelToken) in C:\xxx\Token.cs:line 33
at _7CancellationTokens.Token.<>c__DisplayClass1.<Main>b__0() in C:\xxx\Token.cs:line 22
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
Run Code Online (Sandbox Code Playgroud)
我成功运行的代码在新线程中捕获了OperationCanceledException:
using System;
using System.Threading; …Run Code Online (Sandbox Code Playgroud) .net 4.5 的async-await模式是范式的变化.这真是太好了.
我一直在将一些IO重的代码移植到async-await,因为阻塞已成为过去.
相当多的人正在比较async-await和僵尸感染,我发现它相当准确.异步代码喜欢其他异步代码(您需要异步函数才能等待异步函数).因此,越来越多的函数变得异步,并且在代码库中不断增长.
将函数更改为异步是一种重复性和缺乏想象力的工作.async在声明中抛出一个关键字,包装返回值Task<>,你就完成了.令人不安的是整个过程是多么容易,并且很快文本替换脚本将为我自动化大部分"移植".
现在的问题是..如果我的所有代码都慢慢变为异步,为什么不默认将它全部变为异步?
我假设的显而易见的原因是表现.Async-await有它的开销和代码,不需要异步,最好不要.但是,如果性能是唯一的问题,那么一些聪明的优化肯定可以在不需要时自动消除开销.我已经读过关于"快速路径"优化的内容,在我看来,它应该只关注它的大部分内容.
也许这与垃圾收集者带来的范式转变相当.在GC早期,释放自己的记忆肯定更有效率.但群众仍然选择自动收集,转而采用更安全,更简单的代码,这些代码可能效率较低(甚至可能不再适用).也许这应该是这样的情况?为什么不能将所有函数都异步?
据我所知,yield关键字,如果从迭代器块内部使用,它会将控制流返回给调用代码,当再次调用迭代器时,它会从中断处继续.
此外,await不仅等待被调用者,而且还将控制权返回给调用者,仅在调用者调用awaits方法时从中断处获取.
换句话说 - 没有线程,async和await的"并发"是一种由巧妙的控制流引起的错觉,其细节被语法隐藏.
现在,我是一名前汇编程序员,我对指令指针,堆栈等非常熟悉,并且我得到了正常的控制流(子程序,递归,循环,分支)的工作方式.但是这些新的结构 - 我没有得到它们.
当await到达,如何运行时知道什么是一段代码接下来应该执行?它是如何知道什么时候可以从它停止的地方恢复的,它如何记住在哪里?当前的调用堆栈会发生什么,它会以某种方式保存吗?如果调用方法在其之前进行其他方法调用,那么该await怎么办?为什么堆栈不会被覆盖呢?在异常和堆栈展开的情况下,运行时如何在所有这些中运行?
何时yield到达,运行时如何跟踪应该拾取事物的点?迭代器状态如何保存?
asynchronous ×10
c# ×6
async-await ×4
javascript ×4
.net ×2
promise ×2
async-ctp ×1
concurrency ×1
for-loop ×1
jquery ×1
node.js ×1
reactjs ×1