Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/384.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_Asynchronous_Callback - Fatal编程技术网

如何在Javascript中将异步(基于回调)函数的执行包装到同步函数中?

如何在Javascript中将异步(基于回调)函数的执行包装到同步函数中?,javascript,asynchronous,callback,Javascript,Asynchronous,Callback,我正在尝试用Javascript编写一个函数(如果需要,可以使用jQuery): 此函数依赖于第二个预定义且不可修改的函数,如下所示: function load(callback) { /* ... */ } 此函数是异步的。在调用它之后,它通过XHR获取n个项目,当它们到达时,将它们存储在DOM中,然后调用回调 fetchItem使用一个简单的jQuery选择器(此处不相关)检查具有itemId的元素的DOM,如果该项还不存在,则调用load。冲洗并重复 我的问题是,我想将load的多个异

我正在尝试用Javascript编写一个函数(如果需要,可以使用jQuery):

此函数依赖于第二个预定义且不可修改的函数,如下所示:

function load(callback) { /* ... */ }
此函数是异步的。在调用它之后,它通过XHR获取n个项目,当它们到达时,将它们存储在DOM中,然后调用回调

fetchItem
使用一个简单的jQuery选择器(此处不相关)检查具有
itemId
的元素的DOM,如果该项还不存在,则调用
load
。冲洗并重复

我的问题是,我想将
load
的多个异步调用包装到我的同步
fetchItem
函数中,该函数应该在发出足够的
load
调用后返回带有
itemId
的DOM元素

伪代码,如果加载是同步的:

function fetchItem(itemId):
    while not dom.contains(itemId):
        load()
    return dom.find(itemId)
我第一次尝试在Javascript中实现这一点,这可能显示了对Javascript闭包和执行模型的许多误解:;)

显然,这会失败,因为
返回
是在第一次回调之前执行的。另外,您可以看到,我在将
match
返回到
fetchItem
时遇到了一些问题。这里的封闭是否对其进行了适当的保护?假设
load
支持这一点(并且不会混淆DOM),如果fetchItem并行执行多次,这会起作用吗


我可能错过了一个完美的模式,但我真的不知道用谷歌搜索什么…

这是不可能的。不能从异步创建同步。为什么不向
fetchItem
-函数中添加一个回调呢?

您也需要使fetchItems异步并为其提供一个回调,类似的操作可能会起作用(警告未测试!):


我只想将fetchItem函数作为回调函数来加载。像这样:

function fetchItem(itemId, callback):
    if not dom.contains(itemId):
        load(fetchItem)
    else:
        callback(dom.find(itemId))

callback()是一个函数,当DOM中出现必要的元素时,它会执行其余的工作。

似乎每个人都同意我需要引入自己的回调,所以这里是我(目前为止的最终)工作解决方案:

var MAX_FETCH_MORE = 3;

/*
 * Searches for itemId, loading more items up to MAX_FETCH_MORE times if necessary. When
 * the item has been found or the maximum reload count has been reached, the callback
 * is invoked, which is passed the DOM object of the item wrapped in a jQuery object, or
 * undefined.
 */
function executeWithItem(itemId, callback, fetchCycleCounter) {
    // initialize fetchCycleCounter on first iteration
    if(!fetchCycleCounter) fetchCycleCounter = 0;
    console.debug('iteration ' + fetchCycleCounter + '/' + MAX_FETCH_MORE);

    // try to find the item in the DOM
    match = $('div[data-item-id="' + itemId + '"]').get(0);
    if(match) {
        // if it has been found, invoke the callback, then terminate
        console.debug('found: ' + match);
        callback($(match));
    } else if(!match && fetchCycleCounter < MAX_FETCH_MORE) {
        // if it has not been found, but we may still reload, call load() and pass it
        // this function as the callback
        console.debug('fetching more...');
        load(function() {executeWithItem(itemId, callback, fetchCycleCounter+1);});
    } else {
        // give up after MAX_FETCH_MORE attempts, maybe the item is gone
        console.debug('giving up search');
    }
}

// example invocation
executeWithItem('itemA01', function(item) {
    // do stuff with it
    item.fadeOut(10000);
});
var MAX\u FETCH\u MORE=3;
/*
*搜索itemId,如有必要,加载更多项目最多最多可获取更多次。什么时候
*已找到该项或已达到最大重新加载计数,回调
*调用,传递包装在jQuery对象中的项的DOM对象,或
*未定义。
*/
函数executeWithItem(itemId、回调、fetchCycleCounter){
//在第一次迭代时初始化fetchCycleCounter
如果(!fetchCycleCounter)fetchCycleCounter=0;
调试('iteration'+fetchCycleCounter+'/'+MAX\u FETCH\u MORE);
//尝试在DOM中查找该项
match=$('div[data item id=“”+itemId+“]”)获取(0);
如果(匹配){
//如果已找到,则调用回调,然后终止
调试('found:'+匹配);
回调($(匹配));
}如果(!match&&fetchCycleCounter

感谢大家鼓励我再次进行回调,结果并没有那么糟糕。:)

回调本身从异步例程创建同步性,不是吗?事情一件接一件地发生。@Orbling:不,不是这样的。您无法预测两个异步调用中的哪一个首先完成(这将是同步的)。不可以,但您可以设置代码,使给定的代码段跟随一个异步调用,甚至在发生多个异步调用之后。唯一值得怀疑的是启动多个异步调用时的返回顺序。您可以始终轮询并等待,这样可以同步调用。但是是的,我想再打一次电话是最好的选择。我只需要习惯我的核心逻辑被分解成多个函数。
function fetchItems(itemIDS, callback, matches) {
    if (!matches) { // init the result list 
        matches = [];
    }

    // fetch until we got'em all
    if (itemIDS.length > 0) {
        var id = itemIDS[0]; // get the first id in the queue
        var match = $(id).get(0);

         // not found, call load again
        if (!match) {
            load(function() {
                fetchItems(itemIDS, callback, matches);
            });

        // found, update results and call fetchItems again to get the next one
        } else {
            matches.push(match); // push the current match to the results
            itemIDS.shift(); // remove the current id form the queue
            fetchItems(itemIDS, callback, matches);
        }

    // we have all items, call the callback and supply the matches
    } else {
        callback(matches);
    }
}

fetchItems(['#foo', '#bar', '#test'], function(matches) {
    console.log(matches);
})
function fetchItem(itemId, callback):
    if not dom.contains(itemId):
        load(fetchItem)
    else:
        callback(dom.find(itemId))
var MAX_FETCH_MORE = 3;

/*
 * Searches for itemId, loading more items up to MAX_FETCH_MORE times if necessary. When
 * the item has been found or the maximum reload count has been reached, the callback
 * is invoked, which is passed the DOM object of the item wrapped in a jQuery object, or
 * undefined.
 */
function executeWithItem(itemId, callback, fetchCycleCounter) {
    // initialize fetchCycleCounter on first iteration
    if(!fetchCycleCounter) fetchCycleCounter = 0;
    console.debug('iteration ' + fetchCycleCounter + '/' + MAX_FETCH_MORE);

    // try to find the item in the DOM
    match = $('div[data-item-id="' + itemId + '"]').get(0);
    if(match) {
        // if it has been found, invoke the callback, then terminate
        console.debug('found: ' + match);
        callback($(match));
    } else if(!match && fetchCycleCounter < MAX_FETCH_MORE) {
        // if it has not been found, but we may still reload, call load() and pass it
        // this function as the callback
        console.debug('fetching more...');
        load(function() {executeWithItem(itemId, callback, fetchCycleCounter+1);});
    } else {
        // give up after MAX_FETCH_MORE attempts, maybe the item is gone
        console.debug('giving up search');
    }
}

// example invocation
executeWithItem('itemA01', function(item) {
    // do stuff with it
    item.fadeOut(10000);
});