2017-08-29 146 views
0

我在写一个返回值和数组数组。一些值是在回调中计算的。但我不知道如何使程序异步,因此我的所有结果都在数组中,并且在返回后不会添加。NodeJS在返回之前从异步回调中构造数组

let array = [] 
for (stuff : stuffs) { 
    if (condition) { 
    array.add(stuff) 
    } else { 
    api.compute(stuff, callback(resp) { 
      array.add(resp.stuff) 
    } 
    } 
} 
res.json({ "stuff": array }) 

在这个例子中,在异步调用完成之前,数组被写入响应。

我怎样才能使这项工作异步?

回答

1

你必须使用的方法之一:

  • 异步库
  • Promise.all
  • 协同程序/发电机
  • 异步/等待

最酷劲十足,我认为,是async/await。首先,我们修改的功能,所以它返回一个承诺:

const compute = function(stuff) { 
    return new Promise((resolve, reject) => { 
    api.compute(stuff, callback(resp){ 
     resolve(resp.stuff) 
    }); 
    }); 
}; 

然后,我们用异步处理程序修改您的路线:

app.get('/', async function(req, res, next) { 
    const array = []; 
    for (const stuff of stuffs) { 
    if (condition) { 
     array.add(stuff); 
    } else { 
     const stuff = await compute(stuff); 
     array.push(stuff); 
    } 
    } 
    res.json({ stuff: array }); 
}); 

注:您可能需要节点版本更新到最新版本。

UPDATE:

这些谁没有awared,怎么事件循环工作,执行这个片段,并与完成:

const sleep = async function(ms) { 
    console.log(`Sleeping ${ms}ms`); 
    return new Promise(resolve => setTimeout(resolve, ms)); 
}; 

async function job() { 
    console.log('start'); 

    for (let t = 0; t < 10; t++) { 
    await sleep(100); 
    } 
} 

job(); 

console.log('oops did not expect that oO'); 

你会感到惊讶。

+1

这是一个不好的做法,把异步代码进入一个循环。你应该创造一系列的承诺,然后是'Promise.all'。 (同意异步真棒!) –

+0

它和瀑布一样,它有什么不好? – Lazyexpert

+0

我同意@GrégoryNEUT,在处理异步代码时应避免循环。 –

1

这里是不使用包装回调

创建的会递归处理所有东西的功能答案。

getArray(stuffs, callback, index = 0, array = []) { 
    // Did we treat all stuffs? 
    if (stuffs.length >= index) { 
    return callback(array); 
    } 

    // Treat one stuff 
    if (condition) { 
    array.add(stuffs[index]); 

    // Call next 
    return getArray(stuffs, callback, index + 1, array); 
    } 

    // Get a stuff asynchronously 
    return api.compute(stuffs[index], (resp) => { 
    array.add(resp.stuff); 

    // Call next 
    return getArray(stuffs, callback, index + 1, array); 
    }); 
} 

如何称呼呢?

getArray(stuffs, (array) => { 
    // Here you have your array 
    // ... 
}); 

编辑:更多的解释


我们想要做的改变您必须为一个循环,处理异步函数调用的循环是什么。

目的是要求一个getArray调用你的stuffs阵列的索引。

处理完一个索引后,该函数会再次调用自身来处理下一个索引,直到所有对象都得到处理。

-> Treat index 0 -> Treat index 1 -> Treat index 2 -> Return all result 

我们正在使用参数传递过程中的信息。 Index知道我们必须对待哪个阵列部分,并且保留我们计算的一小部分。


编辑:提高到100%异步soluce


我们在这里做了它的初始for循环的一个简单的换位成异步代码。它可以通过完全异步进行改进,这使它更好,但稍微困难一些。

例如:

// Where we store the results 
const array = []; 

const calculationIsDone = (array) => { 
    // Here our calculation is done 
    // --- 
}; 

// Function that's gonna aggregate the results coming asynchronously 
// When we did gather all results, we call a function 
const gatherCalculResult = (newResult) => { 
    array.push(newResult); 

    if (array.length === stuffs.length) { 
    callback(array); 
    } 
}; 

// Function that makes the calculation for one stuff 
const makeCalculation = (oneStuff) => { 
    if (condition) { 
    return gatherCalculResult(oneStuff); 
    } 

    // Get a stuff asynchronously 
    return api.compute(oneStuff, (resp) => { 
    gatherCalculResult(resp.stuff); 
    }); 
}; 

// We trigger all calculation 
stuffs.forEach(x => x.makeCalculation(x)); 
+0

你能解释这个背后的想法吗?它是否工作,因为最后的回报块?为什么不以另一种方式阻止呢? – aclokay