理解JavaScript中的promise

时间:2014-05-21 00:57:39

标签: javascript promise

我编写了很多JavaScript代码,虽然我认为我确实理解了承诺的运作,但我不确定我是否完全理解承诺给JS世界带来的好处。考虑下面的代码,简单地使用包含更多调用的回调进行异步调用,等等。

(function doWorkOldSchool() {

    setTimeout(function() {

        // once done resolve promise

        console.log("work done");

        setTimeout(function goHome() {

            // once done resolve promise

            console.log("got home");

            try {

                setTimeout(function cookDinner() {

                    // this exception will not be caught

                    throw "No ingredients for dinner!";
                    console.log("dinner cooked");

                    setTimeout(function goToSleep() {

                        // once done resolve promise

                        console.log("go to sleep");

                    }, 2000);

                }, 2000);

            } catch (ex) {
                console.log(ex);
            }

        }, 2000);

    }, 2000);

}());

我看到的一个问题是:

  1. 在回调中抛出异常是没用的。是否正确的说,当抛出调用发生时,这些抛出调用超出范围,因此异常无法调用并且一直冒泡到顶部?如何处理这种异常?

  2. 第二个问题我看到这个嵌套业务可能会变得非常深,即使你可以在setTimeout代码之外保留回调函数代码,它也可能变得一团糟。

  3. 首先,有人可以澄清是否有其他明显的问题或这种编码的优势?

    现在,下面我准备的程序确实做了同样的事情,但这次使用了promises:

    function doWork() {
    
        return new Promise(function(res, rej) {
    
            // do your asynchronous stuff
    
            setTimeout(function() {
    
                // once done resolve promise
    
                res("work done");
    
            }, 2000);
    
        });
    }
    
    
    function goHome(succ) {
    
        console.log(succ);
    
        return new Promise(function(res, rej) {
    
            // do your asynchronous stuff
    
            setTimeout(function() {
    
                // once done resolve promise
    
                res("got home");
    
            }, 2000);
    
        });
    }
    
    
    function cookDinner(succ) {
    
        console.log(succ);
    
        //if exception thrown here it will be caught by chained err handler
        throw "No ingredients for dinner Exception!";
    
        return new Promise(function(res, rej) {
    
            // do your asynchronous stuff
    
            setTimeout(function() {
    
                // something went wrong so instead of using throw we reject the promise
    
                rej("No ingredients for dinner!");
    
                // once done resolve promise
    
            }, 2000);
    
        });
    }
    
    
    function goToSleep(succ) {
    
        console.log(succ);
    
        return new Promise(function(res, rej) {
    
            // do your asynchronous stuff
    
            setTimeout(function() {
    
                // once done resolve promise
    
                res("zzz... zz..");
    
            }, 2000);
    
        });
    }
    
    
    doWork()
        .then(goHome)
        .then(cookDinner)
        .then(goToSleep)
        .then(function(succ) {
    
            console.log(succ);
    
        }, function(err) {
            console.log(err);
        });
    

    与之前的解决方案相比,我发现这种方法没有明显的问题,除了你显然必须理解承诺编码/维护这个东西。然而,优点是:

    1. 抛出的异常INSIDE OF处理程序将被捕获在更进一步链接的错误处理程序中。

    2. 被拒绝的Promise将被链式错误处理程序

    3. 捕获
    4. 代码更清晰

    5. 现在,我的理解是正确的还是每种方法还有其他优点/缺点?

2 个答案:

答案 0 :(得分:0)

您的代码使用了一些反模式,您永远不应该在应用程序代码中创建承诺(例如,通过new Promise," deferreds"等等)。你也必须永远不要将回调与promises混合,因为那样你就会失去异常冒泡(承诺点)并使你的代码变得非常冗长。

您可以自己使用库或实施延迟:

function delay(ms, val) {
     return new Promise(function(res){setTimeout(res.bind(null, val), ms);});
}

然后:

function doWork() {
    return delay(2000, "work done");
}

doWork()
    .then(function(succ) {
        console.log(succ);
        return delay(2000, "got home");
    })
    .then(function(succ) {
        console.log(succ);
        // Never throw strings, yet another anti-pattern
        throw new Error("No ingredients for dinner Exception!");
        // Pointless to add code after throw
    })
    .then(function(succ) {
        return delay(2000, "zzz.. zz..");
    })
    // Don't use the second argument of .then, use .catch
    .catch(function(err) {
        console.log("error: ", err);
    });

为什么要使用.catch而不是第二个参数?好吧,与你同步编写它的方式相比:

try {
    doWork();
    console.log("work done");
    sleep(2000);
    console.log("got home");
    sleep(2000);
    throw new Error("No ingredients for dinner Exception!";)
    sleep(2000);
    console.log("zzz.. zz..");
}
catch(e) {
    console.log("error: ", err);
}

得到它?

答案 1 :(得分:-1)

Promise只能返回/决定一次值,所以一旦选择了一个值就无法更改。因此,如果用户点击div,则Promise仅执行一次 例如:

p = new Promise(function (res, rej) { 
var b = document.getElementById('helloWorld'); 
  b.onclick = function() {
    res(prompt('value'));
  }; 
});
p.then(function(val) { console.log(val); });

日志中始终只有一个值。 这对于游戏/应用程序的GUI和控件非常有用。 你也可以在Promise中有两个事件监听器,这对于加载图像和文件很有用。即使在添加成功或失败处理程序之后Promise也会做出反应,所以你创建了一个成功的函数,虽然失败函数是在以后创建的,如果失败,普通事件处理程序会产生错误,尽管Promises不会,并且稍后调用函数它被创造了。这使您可以更专注于如何对事件做出反应而不用担心事情的时间安排。对于装载东西非常有用 Amazing Page On Promises