使用Promise Q库实现异步JavaScript编程的最佳实践

3

已经在JS中有一层帮助实现向服务器进行Get和Post请求的方法,具体实现如下:

var getJson = function(url, callback, onError) {
    $.get(url)
    .done(function(data) {
        if(callback != null)
            callback(data);
    })
    .fail (function(error) {
        if(onError != null)
            onError (error);
        else
            my.notification.notifyError(onErrorMessage);
    });
};

var postJSON = function(url, data, callback, onError) {
    $.ajax({
        url : url ,
        type: "POST" ,
        contentType : "application/json"
        dataType : "json" ,
        date : ko.toJSON(data)
    })
    .done(function(data) {
        if(callback ! = null)
            callback(data);
    })
    .fail(function(error) {
        if(onError ! = null)
            onError (error);
        else
            my.notification.notifyError(onErrorMessage);
    });
};

在 DataService 层上使用这些实现:

// Get
var find = function(date, onSuccess , onError) {
   var url = /* url with the Controller and Action */ + "?queryString = " + data.filter;
   getJson(url , onSuccess , onError);
};

// Post
var save = function(date, onSuccess , onError) {
    var url = /* url with the Controller and Action */;
    postJSON(url, data, onSuccess, onError);
};

然而,我们使用WebAPI,在某些情况下,一个请求取决于另一个请求的结果,从而形成了“嵌套地狱”。

为了使代码更加优雅,我们正在实现异步编程的Q库。

为了遵循上述模式,使用Q Promises实现了新的Get方法,如下所示:

var getJsonDefer = function(url, callback, onError) {
    return Q.when($.getJSON(url))
    .then (function(data) {
        if(callback ! = null)
            callback(data);
    })
    .fail (function(error) {
        if(onError ! = null)
            onError (error);
        else
            my.notification.notifyError(onErrorMessage);
    });
};

我正在尝试将这个实现方式用于DataService层:

// Get
var find = function(date, onSuccess , onError) {
   var url = /* url with the Controller and Action */ + "?queryString = " + data.filter;
   return getJsonDefer(url, onSuccess, onError);
};

无论如何,在我的层视图模型JavaScript中,假设我需要使用3个查找操作,并且其中一个取决于另一个的结果:

var = dataOne { 
    filter: " Filter"
};

findOne(dataOne,
       function(result) {
            return result;
       }
       function(error) {
           throw error;
       })
       .then(function(args) {
            var = datatwo { 
                filter: args
            };

            // Second
            findTwo(datatwo ,
               function(result) {
                    return result;
               }
               function(error) {
                   throw error;
               }
            );
        })
        .then(function(args) {
            var = dataThree { 
                filter: args
            };

            // Third
            findThree(dataThree,
                function(result) {
                    return result;
                }
                function(error) {
                    throw error;
                }
            );
        }).catch(function(error) {
            // Handle any error from all above steps
        })
        .done();

我的问题:

我承认我无法正确地实现,因为我所有在.then()内的函数都带有未定义的参数。

我想知道遇到这种情况最佳实践是什么。

1个回答

2
我认为您会发现,使用 Promise 的吸引力在于可以用比以前少得多的代码实现您的目标。不过,有几件事情您需要知道。首先,您将不再需要传递或接收回调函数和错误回调函数。您只需要确保在处理程序中返回结果或 Promise 以获得结果即可。这就是值如何传播到下一个处理程序的方式。
以下是您的程序的未经测试的改编版本,应该说明了形式:
var find = function(data) {
    var url = /* url with the Controller and Action */ + "?queryString = " + data.filter;
    return Q($.getJson(url));
};

find({filter: "filter"})
.then(function (firstResult) {
    return find({filter: firstResult})
    .then(function (secondResult) {
        return find({filter: secondResult})
        .then(function (thirdResult) {
            return [firstResult, secondResult, thirdResult];
        });
    });
})
.fail(notifyError)
.done();

请注意,任何阶段的错误都将由底部的单个fail调用处理。无论您是否在最后使用错误处理程序,始终要以done()结束链,以便在控制台中显示发生在之前的任何错误,即使是在您的fail处理程序中发生的错误。
请注意,只有当一个操作取决于先前的操作并且处理程序需要访问第一个和第二个结果时,才需要嵌套承诺。如果您只需要第二个操作的结果,则可以直接链接。
find({filter: "filter"})
.then(function (firstResult) {
    return find({filter: firstResult})
})
.then(function (secondResult) {
    return find({filter: secondResult})
    .then(function (thirdResult) {
        return [secondResult, thirdResult];
    });
});
.fail(notifyError)
.done();

你也可以使用Q.allpromise.spread来展开内容,但是我希望这里留给你阅读文档,因为我希望你能理解要点。


非常感谢你,Kris。"你只需要确保在处理程序中返回结果或结果的承诺。这就是值如何传播到下一个处理程序的 '技巧'。" Javascript及其实现每天都让我着迷。是的,我会继续学习以提高我的知识水平。 - Conrado Fonseca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接