搜索

首页  >  问答  >  正文

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函数实现正确输出的方法

黄舟黄舟2748 天前907

全部回复(6)我来回复

  • 阿神

    阿神2017-07-03 11:43:44

    很遗憾的告诉你,node这边是显式异步的,所以你把一个函数从同步改成异步,那么依赖它的函数也必须做更改,重构的时候确实是个头疼的事情,你还是忍着改改吧。

    像fibjs这种不需要异步关键字的重构起来就很省心了,你改了c不需要改动a和b,因为隐式异步不需要你指示它。

    回复
    0
  • PHP中文网

    PHP中文网2017-07-03 11:43:44

    还是对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函数呢。

    回复
    0
  • 扔个三星炸死你

    扔个三星炸死你2017-07-03 11:43:44

    可以试试 http://fibjs.org/docs/manual/... 直接转成同步即可

    回复
    0
  • 滿天的星座

    滿天的星座2017-07-03 11:43:44

    不得不说我盯着屏幕打了好些草稿, 最终还是失败了.

    我想不出有什么方法能在 js 里阻塞当前函数但是又能及时执行 promise 的 resolve. 失败的思路如下

    c_result=null
    c=async (m)=>{return m+1}
    c_sync = (m)=>{
        let n=0
            pc=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 引擎中新增的事件能被处理.

    回复
    0
  • 巴扎黑

    巴扎黑2017-07-03 11:43:44

    让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;
    }

    回复
    0
  • 世界只因有你

    世界只因有你2017-07-03 11:43:44

    恕我直言,你没有对 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);
    

    回复
    0
  • 取消回复