javascript - nodejs实现异步时遇到的一个问题
黄舟
黄舟 2017-07-03 11:41:44
0
6
935

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

黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全部回复(6)
阿神

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

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

洪涛

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

扔个三星炸死你

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

滿天的星座

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

我想不出有什么方法能在 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 引擎中新增的事件能被处理.

巴扎黑

让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;
}
世界只因有你

恕我直言,你没有对 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);
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板