我想让一个异步进程等待另一个异步进程向其发送信号。 (一次就够了)
在Go中,您可以在两个进程之间创建一个通道。
def foo1(c chan int) {
// do some stuff
c <- 1
}
def foo2(c chan int) {
<-c
// do stuff later
}
基本上<-c
的意思是,“等到有人在c
中放入东西”。 c <- 1
的意思是“在c
中放入1”。 (假设将相同的对象c
传递给两个函数)。
我想用node实现类似的东西。我的想法是创建一个承诺,并有一个过程来解决它,另一个过程是await
。像这样:
function foo1(promise) {
// do some stuff
promise.resolve();
}
function foo2(promise) {
await promise;
// do stuff later
}
我该怎么做?
答案 0 :(得分:1)
您可以使用“ https://www.npmjs.com/package/smem”在异步进程之间发送数据。
// Import.
const SMem = require('smem');
// Create shared memory instance.
const defaultSMem = new SMem();
// Get value async.
(async () => {
console.log(await defaultSMem.get('test-key'));
})();
// Set value after 2 seconds.
setTimeout(() => {
defaultSMem.set('test-key', 'test-value');
}, 2000);
答案 1 :(得分:1)
您可以扩展实现PassThrough
流的Transform
流,并允许您在objectMode
中读写任意数据。从Node v10开始,对Symbol.asyncIterator
的支持已添加到streams中,并允许您使用Readable
循环或手动使用异步迭代器来消耗for await...of
流中的数据next()
,return()
和throw()
方法,它们返回一个Promise<{ value, done }>
。
PassThrough
:module.exports = class Channel extends require('stream').PassThrough {
constructor () {
super({ objectMode : true });
}
async * [Symbol.asyncIterator] () {
const queue = [];
const onData = data => { queue.push(data); };
const next = resolve => {
const onEvent = data => {
this.off('data', onEvent);
this.off('end', onEvent);
resolve();
};
this.on('data', onEvent);
this.on('end', onEvent);
};
this.on('data', onData);
try {
// internals of Readable; indicates whether end event was emitted
while (!this._readableState.ended || queue.length > 0) {
if (queue.length > 0) yield queue.shift();
else await new Promise(next);
}
} finally {
// unsubscribed in finally in case yield returns or throws
this.off('data', onData);
}
}
};
覆盖[Symbol.asyncIterator]
方法是可选的,因为它已经在Readable
流中实现。但是,以上实现允许多个并发接收器使用来自Channel
相同实例的相同数据,而Readable
上存在的默认实现不允许并发接收器使用相同数据。>
const Channel = require('./channel');
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
// source
async function foo1 (c) {
for (let i = 0; i < 10; i++) {
await delay(500);
console.log('foo1', i);
c.write(i);
}
await delay(500);
c.end();
}
// automatic
async function foo2 (c) {
for await (const i of c) {
console.log('foo2', i);
}
}
// manual
async function foo3 (c) {
const asyncIterator = c[Symbol.asyncIterator]();
for (let data; !(data = await asyncIterator.next()).done; ) {
console.log('foo3', data.value);
}
}
const channel = new Channel();
foo1(channel);
// both can consume concurrently
foo2(channel);
foo3(channel);
如果您不关心可重用性,那么扩展Promise
会更容易
class PromiseCompletionSource extends Promise {
static [Symbol.species] = Promise;
constructor () {
const completions = {};
super(
(resolve, reject) => Object.assign(completions, { resolve, reject })
);
this.resolve = completions.resolve;
this.reject = completions.reject;
}
}
function foo1 (c) {
c.resolve(1);
console.log('foo1');
}
async function foo2 (c) {
console.log('foo2', await c);
}
function foo3 (c) {
return c.then(i => {
console.log('foo3', i);
});
}
const channel = new PromiseCompletionSource();
foo1(channel);
foo2(channel);
foo3(channel);
首先打印foo3
的原因是因为await c
实际上是Promise.resolve(c).then(...)
的语法糖,而不仅仅是c.then(...)
,所以foo3()
将解析值延迟了比foo2()
少一分。
答案 2 :(得分:0)
我认为完成此任务的最简单方法是使用EventEmitter
。
这在Node 11.13(once
函数在该版本中)中起作用:
'use strict'
const { EventEmitter, once } = require('events')
const sharedEventEmitterChannel = new EventEmitter()
async function foo1 () {
console.log('do some stuff')
await heavyTask()
sharedEventEmitterChannel.emit('myevent', 1)
console.log('emitted')
}
async function foo2 () {
try {
const num = await once(sharedEventEmitterChannel, 'myevent')
console.log('do stuff later', num)
} catch (err) {
console.log(err)
}
}
foo2()
foo1()
function heavyTask () {
return new Promise(resolve => setTimeout(resolve, 1000))
}
对于早期版本的节点:
'use strict'
const { EventEmitter } = require('events')
const sharedEventEmitterChannel = new EventEmitter()
async function foo1 () {
console.log('do some stuff')
await heavyTask()
sharedEventEmitterChannel.emit('myevent', 1)
console.log('emitted')
}
async function foo2 () {
sharedEventEmitterChannel.once('myevent', (num) => {
console.log('do stuff later', num)
})
}
foo2()
foo1()
function heavyTask () {
return new Promise(resolve => setTimeout(resolve, 1000))
}
答案 3 :(得分:0)
这是我最后找到的解决方案:
async function foo1(resolveFn) {
...
resolveFn();
...
}
async function foo2(promise) {
...
await promise;
...
}
const promise = new Promise(resolve, reject) => {
foo1(resolve);
});
await foo2(promise)