我在弄一个javascript的任务排队,排队中的执行返回是异步的,我要让一个任务依次执行,所以用了while ()来等待之前的一个执行返回。但是这样出现的阻塞,看了点文章,javascript是单线程的,然后也看了settimeout 和 setinterval 介绍。但还是迷茫,这该怎么解决。
类似代码是这样的:
var isOK = true; function createXmlHttpRequest(){  
 if(window.ActiveXObject){ //如果是IE浏览器  
return new ActiveXObject("Microsoft.XMLHTTP");  
 }else if(window.XMLHttpRequest){ //非IE浏览器  
return new XMLHttpRequest();  
 }  
 }
 
var xmlReq = createXmlHttpRequest();//创建一个xmlhttprequest对象

function testAsynRequest() {
var url = "http://xxx.com/test.ashx?ajax=xxuusks";
xmlReq.open("post", url, true);
xmlReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlReq.onreadystatechange = function () {
if (xmlReq.readyState == 4) {
if (xmlReq.status == 200) {
var jsonData = eval('(' + xmlReq.responseText + ')');
alert(jsonData.message);
}
else if (xmlReq.status == 404) {
alert("Requested URL is not found.");
} else if (xmlReq.status == 403) {
alert("Access denied.");
} else {
alert("status is " + xmlReq.status);
}
}
isOK = false;
};
xmlReq.send(null);
} testAsynRequest(); //这里始终没有被响应
while (isOK) { } //这里被先执行了
alert("完成继续下一个执行");

解决方案 »

  1.   

        function testAsynRequest(callback) {
            var url = "http://xxx.com/test.ashx?ajax=xxuusks";
            xmlReq.open("post", url, true);
            xmlReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xmlReq.onreadystatechange = function () {
                if (xmlReq.readyState == 4) {
                    if (xmlReq.status == 200) {
                        var jsonData = eval('(' + xmlReq.responseText + ')');
                        alert(jsonData.message);
                    }
                    else if (xmlReq.status == 404) {
                        alert("Requested URL is not found.");
                    } else if (xmlReq.status == 403) {
                        alert("Access denied.");
                    } else {
                        alert("status is " + xmlReq.status);
                    }
                    if(callback) callback();
                }
            };
            xmlReq.send(null);
        }testAsynRequest(function(){
        alert('前一个ajax已完成');
    });
      

  2.   

    我要让一个任务依次执行简单点,你干脆直接改用同步的 xmlReq.open("post", url, false);
      

  3.   


    用回调嵌套我知道,多几层没关系,但我这里存在一个问题。
    我的这些命令都是调用人家的接口,人家接口的返回是异步的。(web app)
    我的操作其实就是用javascript操作sqlite 通过中间件。具体实际代码:                            execute : function(sql,callback) {
        sqlite.id++;
                                //中间件的异步返回绑定
       uexDataBaseMgr.cbExecuteSql=function(sqldateid,dataType,data){
         if(dataType==2){
           if(data!=0) {
    sqlite.ExeErr = true;
    uexWindow.toast(0, 8, sqldateid + ",执行失败", 2000);
    }
    else {
    if ($.isFunction(callback)) { callback(data); };
    sqlite.isExe[sqlite.ExeLv] = false;
    }
         }

       }
    if (sqlite.ExeLv > 0) { //子层
    sqlite.ExeLv++;
    } else { //主层
    sqlite.ExeLv = 0;
    sqlite.ExeLv++;
    sqlite.isExe[sqlite.ExeLv]=true;
    }
    sqlite.ExeArr.push(sql);
        uexDataBaseMgr.executeSql(sqlite.db,sqlite.id,sql); //这里调用中间件方法的参数是固定的
    while (sqlite.isExe[sqlite.ExeLv]) {
    if (sqlite.ExeErr) {
    alert("语句:"+sqlite.ExeArr[sqlite.ExeLv]+"出错"); sqlite.ExeErr=false; sqlite.ExeLv = 0; break;
    };
    }
    },
    我的任务有可能就是一堆数据库操作
    $.select("select table",function () {
    $.execute("insert 1",callback)
    $.execute("insert 2",callback)
    $.execute("insert 3",callback)
    $.execute("insert 4",callback)
    ...
    });如果我不排队等待的话,插入的永远是 insert 4
      

  4.   

    顶下楼上~
    异步,异步就是不会等返回就立即执行下面的代码,在你的代码中就是:
    testAsynRequest()这一步只是把请求发送出去并规定好不同状态发生时需要弹出哪些东西,但是请求发送出去以后以及在相关页面获取数据并返回数据这一系列过程是靠XMLHttpRequest对象和后台程序完成的(可以理解为暂时脱离js执行环境,在返回数据后又插入js执行环境根据之前规定好的进行弹出)。所以testAsynRequest()执行完后便立即执行while (isOK) { },而请求获取数据的过程则脱离了js线程单独默默地执行,等到状态发生改变得时候,便又立即插入到当前的js线程中按规定好的代码进行执行。
      

  5.   


    ajax 都是你自己写的了,还有什么 不支持同步的 ?
      

  6.   

    不支持同步只好一直嵌套下去了。。$.select("select table",function () {
    $.execute("insert 1",callback)
    $.execute("insert 2",callback)
    $.execute("insert 3",callback)
    $.execute("insert 4",callback)
    ...
    });如果我不排队等待的话,插入的永远是 insert 4 
    -------------------
    感觉是你并发没处理好,是用jquery框架还是自己写的?
      

  7.   

    jquery的框架,但是方法内始终是调用了一个中间件的异步操作,那个操作返回没法是同步,问题就出在这里。
      

  8.   


    你的方法其实可以改成#3的,放到回调函数里面循序依次执行    var arrSql = ['insert 1', 'insert 2', 'insert 3', 'insert 4'/*.....*/]
        , index = 0;    $.select("select table", function () {
            execute(arrSql[index]);
        });
        function callback() {
            index++;
            if (index < arrSql.length) execute(arrSql[index]);
        }
        function execute(sql) {
            $.execute(sql, callback);
        }
      

  9.   


    function xyz(msg) {
     alert(msg);
    }function abc (data,fn) {
      if (data == 1)
        fn.apply("成功");
    }abc(1,xyz);这样算回调吗
      

  10.   


    function xyz(msg) {
     alert(msg);
    }function abc (data,fn) {
      if (data == 1)
        fn.apply("成功");
    }abc(1,xyz);这样算回调吗
    这个确实是回调所以你可以把所有需要做的javascript任务,放在一个list里
    var list = [function(){alert(1)},function(){alert(2)}]然后写一个 doOne 函数,执行list中剩余任务的第一个,并删除它(使第二个成为第一个)
    function doOne(){
    list[0];
    list.splice(0,1);
    }最后,你在每一个任务结束的时候,都去调用 doOne() 就可以了
    因为你是异步的,所以要在异步请求完成后调用 success:function(){doOne()}
    这个 doOne 就是回调函数了
      

  11.   

    看看下面的例子你用得到吗
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script>
    function task1(){
    $.ajax({url:"",
    success:function(){
    alert("task1 异步success完成,点击后执行下一项任务");
    doOne();
    }
    });
    }
    function task2(){
    $.ajax({url:"",
    success:function(){
    alert("task2 异步success完成,点击后执行下一项任务");
    doOne();
    }
    });
    }
    function task3(){
    alert("最后一项完成");
    }
    var list = [task1,task2,task3] doFirst = doOne = function(){
    var fun = list[0];
    list.splice(0,1);
    fun();
    } doFirst();
    </script>