gpt4 book ai didi

JavaScript 生成器风格的异步

转载 作者:搜寻专家 更新时间:2023-11-01 00:02:18 26 4
gpt4 key购买 nike

据我了解, future 在 JS 中编写异步代码的风格是使用生成器而不是回调。至少,或者尤其是。在 V8/Nodejs 社区。是对的吗? (但这可能值得商榷,这不是我在这里的主要问题。)

为了用生成器编写异步代码,我找到了几个库:

它们看起来都很相似,我不确定应该使用哪一个(或者这是否重要)。 (然而,这可能再次值得商榷,也不是我在这里的主要问题——但我仍然会很高兴收到任何建议。)

(无论如何我只使用纯 V8 - 如果这很重要的话。我没有使用 Nodejs 但我在我的自定义 C++ 应用程序中使用纯 V8。但是,我的代码中已经有一些 Node 样式的元素,包括我的自定义 require().)

现在我有一些用回调风格编写的函数 X,它本身调用带有回调参数的其他异步函数,例如:

function X(v, callback) {
return Y(onGotY);
function onGotY(err, res) {
if(err) return callback(err);
return Z(onGotZ);
}
function onGotZ(err, res, resExtended) {
if(err) return callback(err);
return callback(null, v + res + resExtended);
}
}

我想把 X 变成一个生成器,例如我猜 function* X(v) { ... }。那会是什么样子?

最佳答案

我使用了我自己的非常简单的库,它非常适合我的小型 V8 环境,而且由于 JS 调用堆栈保持完整,因此调试起来也很容易。不过,要使其与 Nodejs 或 Web 一起使用,需要进行一些修改。

这里的理由:

对于调试,我们并不是真的想要异步代码——我们希望在调试器中有很好理解的调用堆栈,尤其是。在 Node 检查器调试器中。另请注意,到目前为止,所有异步代码都是完全人工的,我们完全同步地执行所有内容,有点通过 V8 Microtasks 进行模拟。回调式异步代码在调用堆栈中已经很难理解。生成器样式的异步代码在传统调试器中完全丢失了调用堆栈信息——包括与 Node 检查器一起使用的当前 Chrome Beta 开发人员工具 V8 调试器。这就是生成器(通常是协程)的本质。更高版本的调试器可能会处理这个问题,但现在情况并非如此。我们甚至需要一些特殊的 C++ 代码来获取信息。示例代码可以在这里找到: https://github.com/bjouhier/galaxy-stack/blob/master/src/galaxy-stack.cc

因此,如果我们想拥有有用的调试器,今天我们不能使用生成器——至少不能像通常那样使用。我们仍然希望使用生成器样式的异步代码,因为与回调样式的代码相比,它使代码更具可读性。我们引入了一个新函数 async 来克服这个问题。想象一下下面的回调式异步代码:

function doSthX(a, b, callback) { ... }

function doSthY(c, callback) {
doSthX(c/2, 42, function(err, res) {
if(err) return callback(err);
callback(null, c + res);
})
}

现在,使用 async 函数和生成器样式代码的相同代码:

function* doSthX(a, b) { ... }

function* doSthY(c) {
var res = yield async(doSthX(c/2, 42));
return c + res;
}

我们可以提供两个版本的async(iter):

  1. 在栈顶运行迭代器iter。这将保持一个健全的调用堆栈,并且一切都是串行运行的。
  2. 将迭代器交给一些较低的处理程序并使其真正异步。

请注意,有一些著名的库可用于第二种方法:

https://github.com/visionmedia/co http://taskjs.org/ https://github.com/creationix/gen-run https://github.com/bjouhier/galaxy

目前,我们只实现第一种方法 - 使调试更容易。如果我们曾经想同时拥有这两者,我们可以引入一个调试标志来通过这两种实现进行切换。

global.async = async;
function async(iter) {
// must be an iterator
assert(iter.next);

var gotValue;
var sendValue;
while(true) {
var next = iter.next(sendValue);
gotValue = next.value;

if(!next.done) {
// We expect gotValue as a value returned from this function `async`.
assert(gotValue.getResult);
var res = gotValue.getResult();
sendValue = res;
}

if(next.done) break;
}

return {
getResult: function() {
return gotValue;
}
};
}


// Like `async`, but wraps a callback-style function.
global.async_call_cb = async_call_cb;
function async_call_cb(f, thisArg /* , ... */) {
assert(f.apply && f.call);
var args = Array.prototype.slice.call(arguments, 2);
return async((function*() {
var gotCalled = false;
var res;

// This expects that the callback is run on top of the stack.
// We will get this if we always use the wrapped enqueueMicrotask().
// If we have to force this somehow else at some point, we could
// call runMicrotasks() here - or some other waiter function,
// to wait for our callback.
args.push(callback);
f.apply(thisArg, args);

function callback(err, _res) {
assert(!gotCalled);
if(err) throw err;
gotCalled = true;
res = _res;
}

assert(gotCalled);
return res;
})());
}



// get the result synchronously from async
global.sync_from_async = sync_from_async;
function sync_from_async(s) {
assert(s.getResult); // see async()
return s.getResult();
}


// creates a node.js callback-style function from async
global.callback_from_async = callback_from_async;
function callback_from_async(s) {
return function(callback) {
var res;
try { res = sync_from_async(s); }
catch(err) {
return callback(err);
}
return callback(null, res);
};
}


global.sync_get = sync_get;
function sync_get(iter) {
return sync_from_async(async(iter));
}


// this is like in gen-run.
// it's supposed to run the main-function which is expected to be a generator.
// f must be a generator
// returns the result.
global.run = run;
function run(f) {
return sync_get(f());
}

关于JavaScript 生成器风格的异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22449695/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com