Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/412.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在JavaScript中实现异步函数之间的依赖关系?_Javascript_Jquery_Asynchronous_Dependencies_Deferred - Fatal编程技术网

如何在JavaScript中实现异步函数之间的依赖关系?

如何在JavaScript中实现异步函数之间的依赖关系?,javascript,jquery,asynchronous,dependencies,deferred,Javascript,Jquery,Asynchronous,Dependencies,Deferred,作为一个简化的例子,我有两个异步函数,foo和barbar需要foo的结果,即bar取决于foo。我不知道将首先调用哪个函数 如果首先调用bar,bar将调用foo,并在foo完成后立即启动 如果首先调用foo,然后执行,bar可以使用foo的结果 如果先调用foo,然后在foo完成之前调用bar,bar需要等待foo的结果。(不要调用对foo的新调用,只需等待已触发的对foo的调用) 我如何才能做到这一点? 是否可以注册异步函数依赖关系链(类似于require.jsdefine['foo'],

作为一个简化的例子,我有两个异步函数,
foo
bar
bar
需要
foo
的结果,即
bar
取决于
foo
。我不知道将首先调用哪个函数

  • 如果首先调用
    bar
    bar
    将调用
    foo
    ,并在
    foo
    完成后立即启动
  • 如果首先调用
    foo
    ,然后执行,
    bar
    可以使用
    foo
    的结果
  • 如果先调用
    foo
    ,然后在
    foo
    完成之前调用
    bar
    bar
    需要等待
    foo
    的结果。(不要调用对
    foo
    的新调用,只需等待已触发的对
    foo
    的调用)
  • 我如何才能做到这一点?
    是否可以注册异步函数依赖关系链(类似于require.js
    define['foo'],function(){bar();}
    )中的依赖关系?
    我可以使用
    $.deferred()
    来实现它吗?

    怎么做

    您可以简单地认为这两个函数是独立的。这样,就不会对异步运行的依赖项进行菊花链。然后,您可以使用另一个模块

    <>因为他们做了一些事情,考虑使用承诺。为了兼容性,可以使用jQuery的延迟。将延迟视为读/写,而承诺是只读的

    // foo.js
    define(function(){
      return function(){
        return new Promise(function(resolve, reject){
          // Do async stuff. Call resolve/reject accordingly
        });
      };
    });
    
    // bar.js
    define(function(){
      return function(){
        return new Promise(function(resolve, reject){
          // Do async stuff. Call resolve/reject accordingly
        });
      };
    });
    
    // Your code (Excuse the CommonJS format. Personal preference)
    define(function(require){
    
      // Require both functions
      var foo = require('foo');
      var bar = require('bar');
    
      // Use them
      foo(...).then(function(response){
        return bar();
      }).then(function(){
        // all done
      });;
    
    });
    

    在这种情况下,标准方法是缓存较低级别的承诺

    通常,您将在某个合适的外部作用域中建立一个js普通对象作为承诺缓存,并在调用异步进程之前始终首先查看该对象

    var promiseCache = {};
    
    function foo() {
        if(!promiseCache.foo) {
            promiseCache.foo = doSomethingAsync();
        }
        return promiseCache.foo;
    }
    
    function bar() {
        return foo().then(doSomethingElseAsync);
    }
    
    当然,如果合适的话,也没有什么可以阻止您缓存更高级别的承诺

    function bar() {
        if(!promiseCache.bar) {
            promiseCache.bar = foo().then(doSomethingElseAsync);
        }
        return promiseCache.bar;
    }
    
    编辑:
    强制刷新
    功能

    通过传递(额外)参数,可以强制函数刷新其缓存承诺

    function foo(any, number, of, other, arguments, forceRefresh) {
        if(forceRefresh || !promiseCache.foo) {
            promiseCache.foo = doSomethingAsync();
        }
        return promiseCache.foo;
    }
    
    通过使
    forceRefresh
    成为最后一个参数,省略它与传递
    false
    相同,
    foo
    将使用缓存的承诺(如果可用)。或者,传递
    true
    以保证调用
    doSomethingAsync()
    并刷新缓存的值

    编辑2:setName()/getName()

    getName()
    中使用
    forceRefresh
    机制时:

    或者,省略
    forceRefresh
    机制,并假设缓存属性为
    promiseCache.name

    setName(newName).then(getName.bind(null, true)); //set new name then read it back using forceRefresh.
    
    setName(newName).then(function() {
        promiseCache.name = $.when(newName);//update the cache with a simulated `getName()` promise.
    });
    

    第一种方法更优雅,第二种方法更有效。

    尝试使用可能的值创建对象属性
    undefined
    “pending”
    true
    ;当
    obj.active
    true
    时调用
    deferred.resolve()
    obj.active
    为“挂起”时调用
    deferred.reject()

    var res={
    活动:无效0
    };
    var foo=函数foo(状态){
    变量t;
    var deferred=函数(类型){
    返回延迟的美元(函数(dfd){
    如果(res.active==“pending”| | state&&state==“pending”){
    res.active=“待定”;
    dfd.rejectWith(res,[res.active])
    }否则{
    res.active=状态| |“待定”;
    t=设置间隔(函数(){
    console.log(res.active)
    }, 100);
    setTimeout(函数(){
    净间隔(t)
    res.active=true;
    dfd.resolveWith(res,[res.active])
    }, 3000);
    }
    返回dfd.promise()
    })
    .then(功能(状态){
    日志(“foo值”,状态);
    返回状态
    },函数(err){
    日志(“foo状态”,err)
    返回错误
    })
    }
    返回延迟()
    }
    变量栏=功能栏(结果){
    var deferred=函数(类型){
    返回延迟的美元(函数(dfd){
    if(结果&&result==true){
    setTimeout(函数(){
    dfd.resolveWith(结果,[true])
    }, 1500)
    }否则{
    dfd.rejectWith(res[res.active | | |“pending”]))
    };
    返回dfd.promise()
    })
    }
    return deferred().then(函数(数据){
    console.log(“条值”,数据);
    },函数(err){
    控制台日志(“条形图状态”,错误);
    })
    }
    $(“按钮”)。单击(函数(){
    $(this).is(“:first”)
    ?foo()。然后(巴,巴)
    :bar(res.active==true?res.active:“待定”)
    然后(foo,foo),然后(bar,bar)
    })

    bar
    我不确定我是否正确理解了这个问题。但我的看法是:

    • 将函数foo放入变量中

      var foo\u fn=function foo(foo\u args){//异步代码在这里}

    • foo是异步的,并在某个点返回某些内容。在您对foo的定义中,我建议您使用promissions,该概念旨在以干净且可伸缩的方式管理异步函数的组合。这个概念的jQuery实现在许多简单的用例中都很方便,但也有一些缺点,这使得您在某些时候使用遵循promises/a规范的众多promises库中的一个很有意思。有关更多信息,请参阅: 比照及

    • 因此,假设foo接受args,并返回一个承诺,该承诺随后解析为某个值

      var foo\u fn=函数foo(foo\u args){
      return foo_fn.promise=新的RSVP.promise(解析,拒绝){
      //异步代码在这里 } }

      这里我使用RSVP承诺库,但是任何遵循承诺/A规范的承诺库都可以完成这项工作

    • 调用bar时,您只需执行以下操作:

      功能条(条参数){
      var foo_promise=foo_fn.promise;
      //如果调用了foo,无论计算正在进行还是已完成,
      //foo_fn.promise字段将不为空,因为foo会立即返回
      //随时都有承诺