Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/459.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 延续传递样式与并发_Javascript_Multithreading_Haskell_Asynchronous_Concurrency - Fatal编程技术网

Javascript 延续传递样式与并发

Javascript 延续传递样式与并发,javascript,multithreading,haskell,asynchronous,concurrency,Javascript,Multithreading,Haskell,Asynchronous,Concurrency,我发现很多博客都提到并发/非阻塞/异步编程是延续传递风格(CPS)的一个优点。我不明白为什么CPS提供并发性,例如,人们提到Node.js是使用CPS实现的,尽管JavaScript是一种同步语言。有人会评论我的想法吗 首先,我对CPS的天真理解是,将某一点上的所有后续代码包装到一个函数中,并将该函数显式地作为参数传递。一些博客将continuation函数命名为return(),Gabriel Gonzalez称之为a,这两个都是精彩的解释 我的困惑主要来自一篇流行的博客文章。在本文的开头,A

我发现很多博客都提到并发/非阻塞/异步编程是延续传递风格(CPS)的一个优点。我不明白为什么CPS提供并发性,例如,人们提到Node.js是使用CPS实现的,尽管JavaScript是一种同步语言。有人会评论我的想法吗

首先,我对CPS的天真理解是,将某一点上的所有后续代码包装到一个函数中,并将该函数显式地作为参数传递。一些博客将continuation函数命名为
return()
,Gabriel Gonzalez称之为a,这两个都是精彩的解释

我的困惑主要来自一篇流行的博客文章。在本文的开头,Axel Rauschmayer博士给出了两个代码片段,一个是同步程序,另一个是CPS中的异步程序(粘贴在此处以便于阅读)

同步代码:

function loadAvatarImage(id) {
    var profile = loadProfile(id);
    return loadImage(profile.avatarUrl);
}
function loadAvatarImage(id, callback) {
    loadProfile(id, function (profile) {
        loadImage(profile.avatarUrl, callback);
    });
}
异步代码:

function loadAvatarImage(id) {
    var profile = loadProfile(id);
    return loadImage(profile.avatarUrl);
}
function loadAvatarImage(id, callback) {
    loadProfile(id, function (profile) {
        loadImage(profile.avatarUrl, callback);
    });
}
我不明白为什么CPS是异步的。在我读了另一篇文章之后,我认为代码可能有一个假设:函数
loadProfile()
loadImage()
本身就是异步函数。那么,使其异步的不是CPS。在中,作者实际展示了
fetch()
的一个实现,它类似于前面博客中的
loadProfile()
fetch()
函数通过调用
req.onreadystatechange
来明确假设底层并发执行模型。这让我想到,可能不是CPS提供了并发性

假设底层函数是异步的,那么我将进入第二个问题:我们可以在没有CPS的情况下编写异步代码吗?考虑函数
loadProfile()
的实现。如果不是因为CPS,它是异步的,为什么我们不能采用相同的机制异步实现
loadAvatarImage()
?假设
loadProfile()
使用
fork()
创建一个新线程,在主线程以非阻塞方式执行时发送请求并等待响应,我们可以对
loadAvatarImage()
执行同样的操作

我给它一个回调函数
updateDOM()
。如果没有
updateDOM()
,将其与CPS版本进行比较是不公平的——CPS版本有关于获取图像后要做什么的额外信息,即
callback
函数,但原始的同步
loadAvatarImage()
没有

有趣的是,@DarthFennec指出我新的
loadAvatarImage()
实际上是CPS:
fork()
是CPS,
act()
是CPS(如果我们明确地给它
updateDOM
),而
loadAvatarImage()
是CPS。该链使
loadAvatarImage()
异步
loadProfile()
loadImage()
不需要是异步或CPS

如果这里的推理是正确的,我能得到这两个结论吗

  • 给定一组同步API,按照CP编码的人不会神奇地创建异步函数
  • 如果底层异步/并发API是以CPS样式提供的,如
    loadProfile()
    loadImage()
    fetch()
    、或
    fork()
    ,则只能以CPS样式编码以确保异步API被异步使用,例如
    返回loadImage(profile.avatarUrl)
    将使
    loadImage()的并发性无效。
  • Javascript简介 Javascript的并发模型是非并行和协作的:

    • Javascript是非并行的,因为它在单个线程中运行;它通过交错多个执行线程来实现并发,而不是实际同时运行它们
    • Javascript是协作的,因为调度器只在当前线程请求时切换到不同的线程。另一种选择是抢占式调度,调度程序决定在任何时候随意切换线程
    通过做这两件事,Javascript避免了许多其他语言无法避免的问题。并行代码和非并行抢先调度代码不能做出基本假设,即变量在执行过程中不会突然改变它们的值,因为另一个线程可能同时在同一个变量上工作,或者调度器可能决定在任何地方交替地插入另一个线程。这会导致互斥问题和混乱的竞争条件错误。Javascript避免了所有这些,因为在协作调度系统中,程序员决定所有交织发生的位置。这样做的主要缺点是,如果程序员决定长时间不创建交织,其他线程就永远没有机会运行。在浏览器中,甚至像轮询用户输入和页面绘图更新这样的操作都与Javascript在同一个单线程环境中运行,因此长时间运行的Javascript线程将导致整个页面无响应

    起初,在Javascript中,CPS最常用于事件驱动的UI编程:如果您希望在每次有人按下按钮时运行一些代码,那么您可以将回调函数注册到按钮的
    'click'
    事件中;单击按钮时,回调将运行。事实证明,同样的方法也可以用于其他目的。假设你想等一分钟,然后做一件事。天真的方法是将Javascript线程暂停60秒,这(如上所述)将导致页面在此期间崩溃。但是,如果计时器作为UI事件公开,则调度程序可以挂起该线程,同时允许其他线程运行。然后,计时器将以与按钮pre相同的方式执行回调
    run(function() {
        fork(function() {
            console.print("thread 1, first line")
            fork(function() {
                console.print("thread 1, second line")
            })
        })
        fork(function() {
            console.print("thread 2, first line")
            fork(function() {
                console.print("thread 2, second line")
            })
        })
    })
    
    thread 1, first line
    thread 2, first line
    thread 1, second line
    thread 2, second line