JavaScript(异步)如何在继续之前确定要“等待”的内容?

时间:2014-05-22 17:20:16

标签: javascript node.js asynchronous promise q

我最近正在使用JavaScript,我正在试图找出解释器如何确定何时“等待”,以及何时异步进入下一行代码。

拿这两个代码示例。阅读我的评论是因为我的困惑。

1:

function doAThing(thing, callback) {

    var someBoolean;

    if ( !thing ) {
        someBoolean = true;
    } else {
        someBoolean = false;
    }

    // Calling the callback function only happens *after* the above if statement,
    // meaning the interpreter waits instead of just calling it immediately?
    callback(someBoolean);
}

2:

function doOtherThing(thing, callback) {
    var someBoolean;

    // Some fake ORM, querying a fake DB with a where clause of thing
    Model.find().where({ someProperty: thing }).exec(function(err, results){

        if ( results ) {
            someBoolean = true;
        } else {
            someBoolean = false;
        }

    });

    // Calling the callback function happens *immediately* and does NOT wait for
    // someBoolean to get a value inside the ORM query above before it proceeds,
    // so the callback function is given an undefined value for someBoolean 
    callback(someBoolean);

}
  • 在示例1中,为什么/如何在调用回调函数之前等待if语句完全执行?
  • 你如何确定JavaScript将要“等待”的内容,以及它不会等待的内容?
  • 在没有使用Q,Async等库的​​情况下,在本机javascript中更优雅地处理此控制流的策略是什么?

我可能有一些错误的术语,随时纠正我。我来这里是为了尝试理解它,并感谢任何建议。我也有兴趣阅读有关JavaScripts异步的任何资源,但不知道在哪里看。

干杯!

编辑:我理解在示例#2中我可以“强制”回调仅在someBoolean有一个值时通过在ORM查询结束时放置回调调用来调用。然而,这通常很容易变得难以处理。这是示例#3:

function doSomething(thing, callback) {
    // Some fake ORM, querying a fake DB with a where clause of thing
    Model.find().where({ someProperty: thing }).exec(function(err, results){
        ModelTwo.find().where({ somethingElse: thing }).exec(function(err, results){
            ModelThree.find().where({ somethingElse: thing }).exec(function(err, results){
                ModelFour.find().where({ somethingElse: thing }).exec(function(err, results) {
                    // Tons and tons of nesting, getting ever-more-confusing
                    // and pushing my code further to the right....
                    callback();
                });
            });
        });
    });
}

这是一个非常复杂的例子,但在使用Node之前我遇到过这样的情况。当我必须在数据库上运行多个查询或多次与某些外部服务交互时,它会变得非常混乱,最后我需要调用回调...

我想我的问题是:在本机javascript中,是否有更好的方法可以避免所有这种嵌套废话,或者我应该只使用Q或Async这样的promise库?

我想在本机JS中更像这样的控制流:

function doAThing(thing, callback) {
    var bool1, bool2, bool3, bool4;

    SomeLib.someAction().exec(function(err, results){
        bool1 = false;
    });

    SomeLib.someOtherAction().exec(function(err, results){
        bool2 = true;
    });

    SomeOtherLib.action().exec(function(err, results){
        bool3 = false;
    });

    SomeOtherLib.delete().exec(function(err, results){
        bool4 = true;
    });

    // I'd like this only to be called when the above 4 actions are complete,
    // **without** nesting all of the actions together and calling the
    // callback at the end of the last one. As far as I understand it now...
    // I will need a library like async or q in order to have a
    // control flow like this?
    callback(bool1, bool2, bool3, bool4);
}

2 个答案:

答案 0 :(得分:2)

错误,JavaScript完全同步。您的代码示例中没有任何代表解释器是否涉及是否等待;有没有等待。两个示例中的每个语句都将按顺序执行而不会被中断。有些函数会阻塞,有些则不会,但这不取决于解释器。

if ( !thing ) {
   someBoolean = true;
} else {
    someBoolean = false;
}


// Calling the callback function only happens *after* the above if statement,
// meaning the interpreter waits instead of just calling it immediately?
callback(someBoolean);

如果功能阻止,则阻止。您不必担心它,您的代码只是按照从上到下的执行顺序进行。

var someBoolean;

// Some fake ORM, querying a fake DB with a where clause of thing
Model.find().where({ someProperty: thing }).exec(function(err, results){

    if ( results ) {
        someBoolean = true;
    } else {
        someBoolean = false;
    }
});

// Calling the callback function happens *immediately* and does NOT wait for
// someBoolean to get a value inside the ORM query above before it proceeds,
// so the callback function is given an undefined value for someBoolean 
callback(someBoolean);

这是对的。您应该在您传递给ORM的函数内调用callback。您需要在结果准备好时调用回调,这就是回调的全部要点。你的函数不需要立即调用它的回调,这会破坏目的。

  

你如何确定JavaScript将要“等待”的内容,以及它不会等待的内容?

阅读文档。如果它接受回调函数,那可能就是它如何将值传递给你的代码。

  

在原生javascript中更优雅地处理此控制流的一些策略是什么,而不使用Q,Async等库?

......你的意思是什么?你传递了一个回调函数。如果你想要比这更复杂,你应该使用库,如Q,Async等。

答案 1 :(得分:1)

了解事件的工作方式,因为js中的所有异步都涉及事件和事件侦听器。它与将回调作为参数传递然后在函数内部调用它们无关。

异步代码的工作原理如下:

  • 一个函数注册一个事件监听器和一个事件处理程序,然后它就完成并返回
  • 当它侦听的事件触发时,事件处理程序将转到在单个线程中执行的代码列表的末尾,按照它们发生的顺序逐个执行。

想象一下,您作为单个线程运行的所有代码,一行执行。您在该代码中注册的任何事件监听器都会在您的初始化代码中的所有其他内容执行后执行,它无法在两者之间执行,就像两个事件无法同时处理一样。

你所做的所有例子都是围绕一些角落引导线程,围绕一个函数汇集它,可能会打结但是它们并没有真正“突破”那个线程。另一方面,如果你只是使用

setTimeout(yourCallback,0);

然后你突然异步。你的回调将转到等待线的末尾,并且必须等到当前代码的每一部分都被执行并且“没有别的事情要做”,所以它可以进入下一行等待或空闲,等待要发生的事件。