Javascript 在Breeze/Angular中保持异步查询顺序

Javascript 在Breeze/Angular中保持异步查询顺序,javascript,ajax,angularjs,breeze,Javascript,Ajax,Angularjs,Breeze,我使用BreezeJS处理ng网格的服务器端过滤。为此,我只需$watch“查看ng网格过滤器的更改,并使用BreezeJS刷新数据。但是,如果我输入的速度足够快,AJAX查询最终可能会出错 我正在考虑将GUID与每个查询关联起来(通过闭包),并跟踪上次发出的查询请求的GUID。然后忽略返回的与该GUID不匹配的任何查询(我不需要过时的查询结果,只需要最新的查询结果) 但是,是否有更好或更惯用的方法来处理此问题,特别是在Angular/Breeze中?在用户键入时取消以前的任何请求,这样,只有对

我使用BreezeJS处理ng网格的服务器端过滤。为此,我只需
$watch
“查看ng网格过滤器的更改,并使用BreezeJS刷新数据。但是,如果我输入的速度足够快,AJAX查询最终可能会出错

我正在考虑将GUID与每个查询关联起来(通过闭包),并跟踪上次发出的查询请求的GUID。然后忽略返回的与该GUID不匹配的任何查询(我不需要过时的查询结果,只需要最新的查询结果)


但是,是否有更好或更惯用的方法来处理此问题,特别是在Angular/Breeze中?

在用户键入时取消以前的任何请求,这样,只有对当前请求的响应(如果完成)才会更新结果

仅伪代码:

var req;

function search(searchTerm) {
     req && req.cancel();
     req = queryServer().then(resultsReturned);
}

function resultsReturned() {
}

@亚当对你的主要问题有一个重要的想法。。。当用户在搜索框中键入内容时,控制您发出的一连串查询

用户输入去抖动 在开始取消请求之前,应该对搜索条目进行“去盎司”(也称为“节流”)。这意味着在向服务器发出查询之前,等待用户停止键入

在网上搜索“角度”和“去盎司”,你会发现很多技巧。我使用的一个方法是将搜索框绑定到
ngchange=vm.searchChanged()
。然后,ViewModel的
searchChanged
方法将启动
$timeout
。如果用户在1/2秒内输入了任何内容,我会取消该超时并启动另一个超时。在500毫秒的沉默之后,我开始提问。我也会立即开始模糊或如果他们点击回车键

当Angular v.1.3发布时(现在很快),“去盎司”将成为Angular绑定的一部分。我期待着打破我的自制去盎司代码

取消 假设用户停止输入500毫秒,查询开始。。。不耐烦的用户想要取消请求。她不能在《微风》第1.4.11节中那样做。她将能够在第1.4.12节中学习

我刚刚扩展了用于jQuery和Angular的BreezeAJAX适配器,以方便响应请求的取消和超时

响应顺序 在其他情况下,您会启动多个请求。回复不一定会按照您请求的顺序到达。这就是异步的本质

你完全可以自己维持秩序。请记住,您构造了回调。您可以维护一个应用程序范围的请求计数器,为每个查询递增该计数器并保存。。。然后在回调中引用

我写了一个说明性的例子,展示了一种方法:

/*********************************************************
* Dealing with response order
* It's difficult to make the server flip the response order
* (run it enough times and the response order will flip)
* but the logic of this test manifestly deals with it
* because of the way it assigns results.
*********************************************************/
asyncTest("can sequence results that arrive out of order", 3, function() {
    var nextRequestId = 0;
    var em = newEm();
    var promises = [];
    var results = [];
    var arrived = [];

    promises.push(breeze.EntityQuery.from('Customers')
        .where('CompanyName', 'startsWith', 'a')
        .using(em).execute()
        .then(makeSuccessFn()).catch(handleFail));

    promises.push(breeze.EntityQuery.from('Customers')
        .where('CompanyName', 'startsWith', 's')
        .using(em).execute()
        .then(makeSuccessFn()).catch(handleFail));

    function makeSuccessFn() {
        var requestId = nextRequestId++;
        return function success(data) {
            // Don't know which response arrived first?
            // Sure you do. Just refer to the requestId which is a capture
            arrived.push(requestId);
            results[requestId] = data.results;
            assertWhenDone();
        }
    }

    function assertWhenDone() {
        if (results[0] && results[1]) {
            start(); // we're done
            // Here we report the actual response order
            ok(true, "Request #{0} arrived before #{1}".format(arrived[0], arrived[1]));
            // no matter what the response order
            // the 'a' companies go in results slot #0
            // the 's' companies go in results slot #1
            var aCompany = results[0][1].CompanyName();
            var sCompany = results[1][1].CompanyName();
            equal(aCompany[0].toLowerCase(), 'a',
                "company from first batch should be an 'a', was " + aCompany);
            equal(sCompany[0].toLowerCase(), 's',
                "company from second batch should be an 's', was " + sCompany);
        }
    }
});
2015年1月21日更新 我应该提到,
all
promises方法将响应数组传递给
then(…)
success回调,该回调保留请求顺序。如果您碰巧在同一地点同时发出多个查询,并且可以一起等待它们(如上面的示例所示),那么您不需要承担
requestId
的所有繁重工作。就这么做吧

var promises = [];

promises.push(breeze.EntityQuery.from('Customers')
        .where('CompanyName', 'startsWith', 'a')
        .using(em).execute();

promises.push(breeze.EntityQuery.from('Customers')
        .where('CompanyName', 'startsWith', 's')
        .using(em).execute();

// Q.all waits until all succeed or one of them fails
// breeze.Q is typically $q in an Angular app
breeze.Q.all(promises).then(allSucceeded).catch(atLeastOneFail);

function allSucceeded(responses) {
   // response[0] is from the first 'a' query regardless of when it finished.
   // response[1] is from the second 's' query regardless of when it finished.      
}

这肯定是一条路,尽管我不确定微风/安格拉是否可能,这是一个令人惊讶的答案!