例如有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函数实现正确输出的方法
阿神2017-07-03 11:43:44
很遗憾的告诉你,node这边是显式异步的,所以你把一个函数从同步改成异步,那么依赖它的函数也必须做更改,重构的时候确实是个头疼的事情,你还是忍着改改吧。
像fibjs这种不需要异步关键字的重构起来就很省心了,你改了c不需要改动a和b,因为隐式异步不需要你指示它。
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函数呢。
滿天的星座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 引擎中新增的事件能被处理.
巴扎黑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;
}
世界只因有你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);