javascript - nodejs实现异步时遇到的一个问题
问题描述
例如有a,b,c三个函数,分别都执行同步操作,为了简化我把同步操作简化了一下
function c(m) { m = m + 1; return m;}function b(m) { m = m + 1; return c(m);}function a(){ let m = 0; return b(m);}
执行 a() 输出的是2但是如果c函数执行的不是同步函数,是异步操作例如
function c(m) { setTimeout(function () {m = m + 1; }, 1000) return m;}
执行a()时,要想正确输出2,就得把c通过promise或者async进行封装,类似
function promiseC(m) { return new Promise((resolve, reject) => {setTimeout(function () {m = m + 1;resolve(m);}, 1000) }}async function c(m) { m = await promiseC(m); return m; }
因为c变为异步函数,b要调用c,b也要改为异步的,如此类推a也得改为异步
async function b(m) { m = m + 1; return await c(m);}async function a(){ let m = 0; return await b(m);}
a().then(function(data) {
console.log(data)
})这样才能输出2
为了正确输出2,我把a,b都改变了,不知道有没有其他方法可以避免改变a,b又能达到正确输出呢?由于刚开始写代码时没有考虑到异步的情况,像a,b这些函数都是分布到不同文件里面,而且数量比较多,现在为了让c可以执行异步操作,改起来太难了,不知道大家有没有其他好的方法?
下面是新添加的问题利用下面回答中直接返回promise对象的方法可以解决以上的问题,但是实际代码更多的结构是这样的
function c(m) { m = m + 1; return m;}function b(m) { m = m + 1; let n = c(m) n = n + 1 return n;}function a(){ let m = 0; let k = b(m); k = k + 1; return k;}
如果按这个方法,我得改造a,b的return方法才能让a,b返回promise对象,对于这样的结构不知道还有没有不改动a,b函数实现正确输出的方法
问题解答
回答1:很遗憾的告诉你,node这边是显式异步的,所以你把一个函数从同步改成异步,那么依赖它的函数也必须做更改,重构的时候确实是个头疼的事情,你还是忍着改改吧。
像fibjs这种不需要异步关键字的重构起来就很省心了,你改了c不需要改动a和b,因为隐式异步不需要你指示它。
回答2:还是对Promise的理解不到位啊。这里没必要改动b()和a()的。
对于函数c,只需要返回一个promise对象,经过函数b的时候,直接同步返回这个Promise对象,不需要改动函数b使其为异步函数,因为异步操作是在函数c中,b中只进行了同步操作。此时需要在函数a中捕获这个Promise,所以代码可以改成这样
function promiseC(m) { return new Promise((resolve, reject) => {setTimeout(function () { m = m + 1; resolve(m);}, 1000) })}function c(m) { m = promiseC(m); return m;}function b(m) { m = m + 1; return c(m);}function a() { let m = 0; return b(m);}p.then(function(a){ console.log(a)})
所以,这里函数a(),b()如果不处理异步操作的返回值,那为何要把他改成Async函数呢。
回答3:可以试试 http://fibjs.org/docs/manual/... 直接转成同步即可
回答4:不得不说我盯着屏幕打了好些草稿, 最终还是失败了.
我想不出有什么方法能在 js 里阻塞当前函数但是又能及时执行 promise 的 resolve. 失败的思路如下
c_result=nullc=async (m)=>{return m+1}c_sync = (m)=>{ let n=0pc=c(m).then((m)=>{c_result=m}) while(c_result===null && n++<100){} return c_result}b=(m)=>{return c_sync(m+1)}a=()=>{return b(0)}a()
它的问题在于, 虽然while(c_result===null && n++<100){}阻塞了函数c_sync, 但是也阻止了.then回调的执行. 由于单线程异步的机制, 当某一个回调触发的时候, 如果线程正忙, 这个回调是没法插队的, 从而导致循环执行过程中, c_result没办法被变量 m 赋值.也就没办法退出循环.
但是我觉得这个问题很有意思. 找到了一篇相关文章. 作者通过一个外部二进制库结局了局部阻塞的问题.
http://blog.csdn.net/xingqili...
我的理解是:基于 js 引擎自身的事件循环, 我们不能阻塞某个块. 因为对于 js 代码而言引擎的事件循环是在底层. 但是对于外部的二进制模块而言. 其可以阻塞自身, 并保证 js 引擎的事件循环每一次都完全遍历事件队列----以保证自身阻塞期间在 js 引擎中新增的事件能被处理.
回答5:让a()输出promise,确实可以解决我提到的问题但是在真正修改代码的时候,我发现大部分代码的结构不是我上面问题这样的而是下面新补充的结构
function c(m) { m = m + 1; return m;}function b(m) { m = m + 1; let n = c(m) n = n + 1 return n;}function a(){ let m = 0; let k = b(m); k = k + 1; return k;}回答6:
恕我直言,你没有对 node.js 的事件循环机制和 event 核心模块作深入的了解。promise 和 aysnc/await 确实是如今处理异步流程控制的主流,但并不是说没有了它们就做不了了,这种简单的问题回溯到 event 方式处理即可。
const EventEmitter = require(’events’);class MyEmitter extends EventEmitter {}const myEmitter = new MyEmitter();myEmitter.on(’a’, (m) => { console.log(’a -> b’); myEmitter.emit(’b’, m+1);});myEmitter.on(’b’, (m) => { console.log(’b -> c’); myEmitter.emit(’c’, m+1);});myEmitter.on(’c’, (m) => { console.log(’result’, m);});myEmitter.emit(’a’, 0);
相关文章:
1. javascript - 回调函数如何访问当前函数作用下的值2. javascript - H5页面怎么查看console信息?3. tornado - python使用yield是否能保证协程的顺序性?4. android 文件File删除问题5. 绝对定位和fied定位,键盘弹起对布局的影响6. javascript - vue生成一维码?求助!!!!!急7. javascript - 修改表单多选项时和后台同事配合的问题。8. mysql - 索引过滤性不好是由什么原因引起的,应该怎么解决9. nginx英文文档的WebSocket proxying部分没看太明白,麻烦推荐一点中文文章10. 网页爬虫 - Python:爬虫的中文编码问题?
