链接多个承诺(处理回调)

时间:2014-09-24 00:35:59

标签: javascript angularjs promise angular-promise

当链接多个时,我在承诺方面遇到了一些困难。混淆是区分如何正确利用 承诺 &他们与 回调 的区别。我注意到,无论承诺是否得到解决,回调有时会消失,使得下面的实现不可靠..(除非我的语法和逻辑错误)
我阅读官方文档并想出了这个,但我不是确保实施得很好。

注册流程如下:

  • 用户选择别名 - >详细信息别名+ userID(设备的通用唯一标识符)是服务器端发送的
  • 如果Alias可用,则生成ApiKey(令牌),用户注册并发送回客户端(存储在DB中)

Services.js

(function(angular) {
   myApp.factory("deviceDB.Service", ['$resource', '$http', '$q',
   function ($resource,  $http , $q ) {

    return {

//Second Promsie : After API token is generated server-side, store res in db

        RegDevice: function (alias, apiKey, userID) { 
            var deferred = $q.defer();
            var configuration ;
            var db = window.sqlitePlugin.openDatabase({name: "config.db"});
            setTimeout(function () {

                db.transaction(function (tx) {
                    tx.executeSql('CREATE TABLE IF NOT EXISTS user_details (userID UNIQUE , alias TEXT, apiKey TEXT)');
                    tx.executeSql("INSERT INTO user_details (userID, alias, apiKey) VALUES (?,?,?)", [userID, alias, apiKey], function (tx, res) {

                        deferred.resolve(configuration = true);
                    }, function (e) {
                        // console.log("ERROR: " + e.message);
                        deferred.reject(configuration = false);
                    });
                });

            }, 1000);
            return deferred.promise;
        },

//First Promsie: Register user  server side & generate APi token

        RegUser: function (alias, userID) { 

            var deferred = $q.defer();
            var pro;
            pro = $resource('api/query/register', {'alias': alias, 'userID': userID},
                { query: {
                        isArray: false,
                        method: 'GET'  } });

            setTimeout(function () {
                pro.query(function (res) {
                    if (res.error) {
                        deferred.reject( { error : res.error, exists: res.exists,  msg: res.message } );
                    }
                    else {
                        deferred.resolve( {error : res.error , alias: res.alias , apiKey: res.apiKey, msg: res.message } );
                    }
                }, function (e) {
                    deferred.reject( { errorStatus: e.status } );

                });

            }, 1000);
            return deferred.promise;
        }

    };

  }]);

}(window.angular));


现在,在我的控制器中,我想将上述两个承诺链接起来。我引用文档中的以下内容:

then(successCallback, errorCallback, notifyCallback) - 无论何时或将要解决或拒绝承诺,只要结果可用,就会异步调用其中一个成功或错误回调。使用单个参数调用回调:结果或拒绝原因。另外,在解决或拒绝承诺之前,可以将通知回调调用零次或多次以提供进度指示。

  1. 如果无论Promise是否已解决,如果他们可以解雇,那么回调是什么意思?
  2. 我不应该在第一个Promise的成功回调中呼叫例如 Promise2 吗?如果无论 Promise1 被解析,它都会被解雇,那么如何只在解析Promise1 时才能以一种方式链接Promise2 ?< / LI>


    我尝试了什么:
    Controller.js

    myApp.controller('RegisterController', ['$scope', '$http', 'deviceDB.Service',
        function ($scope , $http , deviceDB.Service) {
    
       var Promise1 = deviceDB.RegUser($scope.alias, $scope.Device); 
    
    // First promise - Validate with server
       Promise1.then(function(data)
                        {
                            console.log(' Registration Server-Side successfully');
                            $scope.apiKey = data.apiKey;
                            term.echo(data.apiKey);
    
                        }, function(e)
                        {
                            console.log('Registration Failed');
                            term.echo(e.msg);
    
                        })
    
    //Call Promise 2 & Store details Client-Side using .then()
    
        .then(deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device), 
         function(d){
                           console.log('Items Stored in DB successfully');
                        }, function()
                        {
                            console.log('Items Stored in DB Failed');
                        });
      }]);
    

    注意:我理解在客户端存储详细信息是一种不好的做法,但是,我遵循不同的概念(匿名消息传递)并且没有安全问题。

    感谢您的时间

3 个答案:

答案 0 :(得分:1)

之后,你的第二个电话似乎不正确
//Call Promise 2 & Store details Client-Side using .then()

then最多需要传递3个参数then(successCallback, errorCallback, notifyCallback)deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device)立即进行评估,并将返回的promise作为成功传递给函数then函数,您的成功函数作为errorCallback传递,您的失败函数作为notifyCallback传递。

我会尝试以下

 Promise1.then(function(data)
 {
   console.log(' Registration Server-Side successfully');
   $scope.apiKey = data.apiKey;
   term.echo(data.apiKey);

   return deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device)

 }, function(e)
 {
   console.log('Registration Failed');
   term.echo(e.msg);

   return e;

 }).then(function(d) {/*all good*/}, function(e) {/* all bad */}

请注意,对RegDevice的调用现在位于一个功能块内,并且从您要链接的then块返回一个promise。

答案 1 :(得分:0)

我发现$q.serial是一个很好的链接承诺的图书馆。它非常容易使用并处理很多东西,例如检查链上的所有承诺是否真的是承诺。

这是一个小例子:

function do_all() {                                                         
    var task_1 = function() {                                                  
        return $http.get("some url")                                           
            .then(on_xhr_completed_fn, on_xhr_failed_fn);                      
    }                                                                          

    var task_2 = function(some_data) {                                         
        vm.bla = some_data;                                                    
        return $http.get("other url")                                          
            .then(on_xhr_completed_fn, on_xhr_failed_fn);                      
    }                                                                          

    var task_3 = function(other_data) {                                        
        vm.bli = other_data;                                                   
    }                                                                       

    var tasks = [task_1, task_2, task_3];                                      

    return $q.serial(tasks)                                                    
        .then(function() {                                                     
            console.log("Finished tasks 1, 2 and 3!!!");                       
        });                                                                    
}  

答案 2 :(得分:0)

以下是使用异步/等待的一种方法:

async function run_promise_A(args) {
    return new Promise((resolve, reject) => {
        return resolve(resolve_value)
    });
}

async function run_promise_B(args) {
    return new Promise((resolve, reject) => {
        return resolve(resolve_value)
    });
}

async function run_promise_C(args) {
    return new Promise((resolve, reject) => {
        return resolve(resolve_value)
    });
}

async function run_several_async_functions(userid) {
    let a = run_promise_A(userid);
    let b = run_promise_B(a);
    let c = run_promise_C(b);
    return c;
}

return Promise.resolve()
    .then(() => {
        let c = (async () => {
            let c = await run_several_async_functions(userid)
            return c;
        })();
        return c;
    })
    .then((c) => {
        return c;
    })
    .catch((err) => {
        console.log(err);
    });