javascript - 链接 2 个异步调用(promise API)以串行运行

标签 javascript angularjs promise

这类似于我发布的问题 today ,但需要串行链接的请求。我有两个异步请求,其中第二个请求需要第一个请求的结果来发送查询。

var Db.get = function(key){
    var deferred = $q.defer();

     //send async req
    var req = ....
    req.success = function(d){
        deferred.resolve(d)
    };
    req.failure = function(d){
        deferred.reject(d)
    }

    return deferred.promise;
}

var someFn = function(id){
    Db.get(id, "abc")
        .then(function (d) {
            console.log("At 1")
            Db.get(d.id, "def")
                .then(function (d) {
                    console.log("At 2")
                    return d
                }, function (e) {
                    //error
                });
        }, function (e) {
            //error
        });

    console.log("At 3")
};

我应该是想错了,因为我期望 console.log("At 3") 永远不会在成功场景中打印,因为我在 console.log("At 2"之后返回")。但是当我运行时,在控制台中我看到这些顺序

console.log("At 1")
console.log("At 3")
console.log("At 2")

我在想 then 会阻塞直到它从 promise 中得到响应(由 get() 返回)。因此, someFn 中的所有内容都是串行执行的。这个假设错了吗?将两个使用 promise 的异步操作串联起来串行运行的最佳方法是什么。

谢谢。

编辑:

我尝试了 Ketan 建议的方法 Chaining Ajax calls in AngularJs .

var someFn = function(id){
            Db.get(id, "abc")
                .then(function (d) {
                    console.log("At 1")
                    return Db.get(d.id, "def")
                }).then(function (d) {
                    console.log("At 2")
                    return d
                }, function (e) {
                    //error
                    return null;
                }).then(function (d) {
                    return d;
        });

        console.log("At 3")
    };

不过,如果我像这样打电话

var res = someFn(1)
console.log(res) /// undefined

chrome 终端在 undefined 之后显示 At 2。我不确定为什么 someFn 返回的结果没有分配给 res

最佳答案

您遇到困难的地方是 .then 实际上并没有阻塞。它可以帮助您将同步代码转换为异步代码,但它不会为您这样做。让我们从考虑您要重写的同步代码开始。假设 Db.get 是一个返回值而不是 promise 的同步函数:

var someFn = function (id){
    try {
        var d = Db.get(id, "abc");
        console.log("At 1");
        var d = Db.get(d.id, "def");
        console.log("At 2")
        return d;
    } catch (ex) {
        console.log("At 3")
    }
};

在这种情况下,当我调用 someFn 时,我得到一个值,而不是一个 promise 。也就是说整个函数是同步的。

如果我们暂时快进几年并想象我们可以使用 ES6。这样我们就可以将您的函数重写为:

var someFn = $q.async(function* (id){
    try {
        var d = yield Db.get(id, "abc");
        console.log("At 1");
        var d = yield Db.get(d.id, "def");
        console.log("At 2")
        return d;
    } catch (ex) {
        console.log("At 3")
    }
});

这看起来非常相似,但这次我们让 Db.get 返回一个 promise ,而 someFn() 也将始终返回一个 promise 。 yield 关键字实际上“暂停”当前函数,直到实现 promise 。这让它看起来就像同步代码,但实际上是异步的。

回到现在,我们需要弄清楚如何编写它。 .then 调用的第二个参数是错误处理程序,因此与 ES6 示例完全等效的是:

var someFn = function (id){
    return Db.get(id, "abc")
        .then(function (d) {
            console.log("At 1");
            return Db.get(d.id, "def");
        })
        .then(function (d) {
            console.log("At 2");
            return d;
        })
        .then(null, function (ex) {
            console.log("At 3")
        });
});

注意每个返回是如何只从其当前函数范围返回的。没有办法强制它一直跳出 someFn

另一个有趣的实验是:

Db.get('id', 'abc')
  .then(function () {
    console.log('B');
  });
console.log('A');

以上将始终记录:

A
B

因为 .then 不会阻塞。

关于javascript - 链接 2 个异步调用(promise API)以串行运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16311803/

相关文章:

node.js - Access-Control-Allow-Headers 不允许请求 header 字段进行身份验证

javascript - 在 React 组件中显示并行 Ajax 请求的结果

javascript - 使用异步需要异步功能,但我的功能是异步的

javascript - JavaScript 中的变量 RegEx 字符串替换

javascript - 如何向最终用户隐藏 REST API Url?

javascript - jQuery UI-Resizable 添加不需要的边距

javascript - Extjs - 在 FormPanel 中动态生成字段

javascript - 提交时 AngularJS 中的表单验证不起作用

javascript - 在 Phonegap/ApacheCorova 和 Ionic 框架中构建移动应用程序是否必须使用 Angular.js?

javascript - 如何从 Q.when() 解析一系列分辨率?