b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

最后讨论JavaScript异步编程

电脑杂谈  发布时间:2020-07-11 08:02:30  来源:网络整理

c socket异步编程_linux c/c++异步io_c 异步编程

我们已经过多地讨论了JavaScript的异步编程. 我们已经做了大量的工作来解决“回调地狱”问题. 从Promise到再到异步/等待,JavaScript都不愿意填写. 完成. 关于Promise,generator和aysnc / await如何使用这些特定技术,我在这里不做详细介绍,我们将更多地讨论“形而上学”的事情.

在我们传统的“命令式”编程语言中,我们的思维逻辑通常是按一系列事物来完成的,然后再做另一件事. 要翻译语言,我们通常编写代码的逻辑是执行一行然后执行下一行. 一个程序由一组命令序列组成.

但是,现在问题来了,在JavaScript的设计阶段,为了确保线程安全并确保引擎不会被IO等待阻塞,页面会失去响应,因此我了解了“异步事件模型”,因此“事件模型”是用于解决多线程并行问题的模型.

【注意】实际上,所谓的“异步”并不是JavaScript独有的,而是一种非常成熟,非常古老的模型,已广泛用于电子电路的设计中. 计算机的各种辅助IO设备,特别是慢速IO(例如硬盘),都具有异步事件响应设计的影子.

写了太多线程程序的朋友一定会被这四个词不断地磨碎,但这无非是程与环境之间的爱与恨中挣扎. 这些卵折腾成“信号”,“原子”,伤人的事情. 但是“异步事件模型”很好地解决了这个问题. 此“异步事件模型”具有两个核心功能: 1.只有主线程才有权更改环境. 2.不允许阻塞主线程. 这对于解决线程与环境之间的矛盾非常好. 我们的JavaScript遵循这种设计.

如上所述,“异步事件模型”是解决多线程并行性的模型(当然,该模型不限于多线程,也可以使用多进程,也可以使用集群),这并不难理解,为什么有些甚至不了解多线程的前端会很难理解. 但是,尽管像异步这样的设计已经管理了最令人讨厌的线程管理,但是很难像这样设计一个复杂而灵活的GUI应用程序,但是也有必要理解该设计才能很好地使用它.

这时我们将正式开始我们的主题. 在远古时代,我们的JavaScript异步编程通常是一个洋葱结构,带有一层圆括号和一层像洋葱一样的圆括号,并且还产生了我们熟悉的“回调地狱”. 我将复制一段代码以供查看

c socket异步编程_c 异步编程_linux c/c++异步io

fs.readdir(source, function (err, files) {
  if (err) {
    console.log(Error finding files:  + err)
  } else {
    files.forEach(function (filename, fileIndex) {
      console.log(filename)
      gm(source + filename).size(function (err, values) {
        if (err) {
          console.log(Error identifying file size:  + err)
        } else {
          console.log(filename +  :  + values)
          aspect = (values.width / values.height)
          widths.forEach(function (width, widthIndex) {
            height = Math.round(width / aspect)
            console.log(resizing  + filename + to  + height + x + height)
            this.resize(width, height).write(dest + w + width + _ + filename, function(err) {
              if (err) console.log(Error writing file:  + err)
            })
          }.bind(this))
        }
      })
    })
  }
})

一次一次吗?此代码有什么问题?实际上c 异步编程,说实话没有什么大问题. 实际上,Callback Hell的最大问题实际上不是由于不良的书写和不良的外观而导致的良好管理,而是将代码显示给他人进行维护和管理. 因此,每个人都开始绞尽脑汁想办法.

如上所述,像洋葱这样的逐层结构很难书写和切割,而且非常难看. 随后的问题很难解决. 因此,无论是Promise还是Generator,还是async / await,他们的任务是尽一切可能将这种洋葱结构拉成扁平的线性结构.

首先要谈的是承诺. 首先,使用两段代码来展示诺言的作用.

// 没有 promise
a(getResultFromA, (aResult, err) => {
  if (!err) {
    b(getResultFromB, (bResult, err) => {
      if (!err) {
        c(getResultFromC, (cResult, err) => {
          if (!err) {
            // do something
          } else {
            throw err
          }
        })
      } else {
        throw err 
      }
    })
  } else {
    throw err
  }
})
// 用了 promise 后
new promise((resolve, reject) => {
  a(getResultFromA, (aResult, err) => {
    if (!err) resolve(aResult) else reject(err)
  })
})
.then(data => {
  return new Promise((resolve, reject) => {
    b(getResultFromB, (bResult, err) => {
      if (!err) resolve(bResult) else reject(err)
    })
  }
})
.then(data => {
  return new Promise((resolve, reject) => {
    c(getResultFromC, (cResult, err) => {
      if (!err) resolve(cResult) else reject(err)
    })
  }
})
.then(data => {
  // do something
})
.catch(err => {
  throw err
})

您看到区别了吗? Promise的核心功能是使“洋葱结构”变平. 但是,错误处理和Promise链的使用当然非常有意义. 但是,您一定发现它很聪明. 似乎使用Promise并不能使代码看起来不错,需要编写多少代码?没错,因此有了下一个和async / await. 说到这,Promise的最大贡献实际上是统一了JavaScript异步编程的标准规范.

【注意】我曾经知道前端影响者曾经对我说过“使用Promise时没有回调”. 经过“讨论”,我决定将这位有影响力的人排除在外. 使用Promise后,如果没有回调,Promise的then方法的参数是什么? Promise并没有真正消除回调,Promise只是使用then方法来延迟回调的绑定.

c 异步编程_linux c/c++异步io_c socket异步编程

使用Promise并不能真正消除回调,还添加了许多.then(data => {....})这些无意义的“模板代码”. 因此,那些喜欢折腾的人最终想到了和异步/等待. Generator具有一些神奇的功能,因此,我只想看一下MDN上的文档就不用多说了,但是Generator也可以处理异步(当然,要带上tj / co库),它确实消除了回调的存在.

// 使用 tj/co 库和 generator
co(function *() {
  try {
    const aResult = yield new Promise(/* getResultFromAPromise */)
    const bResult = yield new Promise(/* getResultFromBProimse */)
    const cResult = yield new Promise(/* getResultFromCPromise */)
    // do something
  } catch (err) {
    throw err
  }
})

似乎已经非常易于使用,但是使用来处理异步仍然与tj / co密不可分,并且存在一些错误和兼容性问题. 接下来看async / await

async function () {
  try {
    const aResult = await new Promise(/* getResultFromAPromise */)
    const bResult = await new Promise(/* getResultFromBProimse */)
    const cResult = await new Promise(/* getResultFromCPromise */)
    // do something
  } catch (err) {
    throw err
  }
}

总的来说,使用co库后,async / await看起来与非常相似,但是回调仍然消失了. 代码结构又回到了熟悉的“序列结构”.

在讨论了现有JavaScript异步解决方案的优点之后,下一步就是讨论现有异步解决方案的缺点. 就是说,正如副标题所述,结构和执行是高度耦合的. 这就是为什么我不喜欢JavaScript的现有异步解决方案的原因. 最典型的情况是,如果我需要动态生成异步序列,Promise将无法做好工作. 已生成的Promise序列也不会增加首尾,也不会增加或减少中间承诺. 当然,如果您什么也不想说,我可以编写一堆回调,然后在执行时生成一个promise链,但这失去了使用Promise的意义.

例如,以下是一个简单的代码,描述了如何使结构与执行分离(我从上一个答案中复制了它):

// 定义一个函数 sync 封装一个同步函数进入异步序列。
var sync = function(sync_func){
  return function(data, next){
    next(sync_func(data));
  };
};
// 将一个异步序列组合成一个可以执行的异步函数
var compose = function(async_function_list, callback){
  return async_function_list.reduceRight(function(left, right){
    return function(data){
      right(data, left);
    };
  }, callback);
};
// 异步函数序列
var job_list = [
  function(data, next){
    setTimeout(function(){
      next(data + 1);
    }, 1e3);
  },
  // 用 sync 将同步函数混入异步队列
  sync(function(data){
    return data + 2;
  }),
  function(data, next){
    setTimeout(function(){
      next(data + 3);
    }, 1e3);	
  },
];
// 可以非常方便的给异步函数序列加入新的特性,甚至是错误处理也可以这样加入
// 这里是在每一个异步操作前加入一个 console.log(data) 用来检测每一步的输出。
var job_list_with_process = job_list.map(function(async_job){
  return function(data, next){
    console.log(data);
    async_job(data,next);
  };
})
// 用 compose 函数将异步函数序列串成一个函数,并定义异步序列完成后的 callback
var asyncJob = compose(job_list_with_process, function(data){ 
  console.log(done with:, data)
});
// 执行
asyncJob(0);

上面的代码很好地演示了job_list之类的结构与asyncJob之类的特定操作之间的区别. 我可以在job_list之类的结构中向每个操作添加新功能. 我可以添加标题,可以添加尾部,甚至可以反向执行它们. 这是结构和具体执行脱钩的魔力.

尽管此处使用了类似List的“序列结构”,但从设计的角度来看,它是一致的.

我以前在Monad上写过很多次文章,当我学习Haskell时就接触了Monad的概念. 许多听说过Monad的人都对一个广为流传的声明感到恐惧-“ Monad只是函子类别中的一个半模态. ”这句话完全是针对蒙古外行的,相当于说“人类只是一只有两只眼睛和一只鼻子的动物”,完全是胡说八道.

莫纳德到底是什么?我的水平还不够,我真的无法分辨. 但是Monad在功能上的显示,我仍然可以弄清楚. 在实际应用中,Monad会显示一个可以包含自身的抽象结构,就像封面图片上的洋葱一样.

谈到这一点,聪明的朋友发现了吗? JavaScript的回调地狱在结构上与Monad惊人地相似. Monad和异步是自然而然的,因此有一种叫做Continuation Monad的东西可以处理异步问题. 承诺链实际上是一种延续单子.

【注意】单子只是一个结构,它只是一个结构. 例如,我构建了一个Continuation Monad,然后此Monad仅描述了一个结构,而实际上并未实现. 在特定执行中,将有一个特殊的runXXXMonad方法来逐层“剥洋葱皮”,然后执行.

【注意】实际上c 异步编程,List也是Monad.

我们在上面提到Monad是洋葱结构. Monad还会在代码中出现诸如Callback Hell之类的问题吗?没错,Monad确实存在诸如Callback Hell之类的问题,例如编写一段将Monk逐层包装在Haskell中的代码.

{-- 这是一段简单的 IO Monad,print xx 是一个 Monad --}
print hello >>= (\_ -> print world >>= (\_ -> print haskell))

这段代码将Monad逐层包装,完全是JavaScript Callback Hell的副本. 尽管Haskell的函数定义更简洁,但看起来更好. 那么看看Haskell如何解决他的Monad基本结构之一

{-- 这里用了 do 语法糖 --}
do
  print hello
  print world
  print haskell

您难道不认为`>> = \ _->`当您阅读时,这东西看起来更累了吗?好吧,我为您制作了语法糖. 在do语法块中,回车符是`>> = \ _->`您是否吼叫?这是一个CPS语法糖. 在引擎不更改代码行的前提下,仅提供语法糖就可以完美解决回调地狱的问题. 因此,这就是为什么我说JavaScript实际上只是远离最佳异步解决方案的一种语法.

正如标题所示,这是我最后一次谈到JavaScript异步编程. 老实说,这真是不好的话. 我上面所说的是几年来关于JavaScript异步编程折腾的全部知识. 细节可能不清楚,但是主要思想已经说过了. 保留它作为纪念.

-对于那些被JavaScript淘汰或死亡的年份


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/ruanjian/article-276250-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      • 颜延之
        颜延之

        这么好的军舰不没收太可惜了

      • 李肖飞
        李肖飞

        平时我姑们和孙子辈的买点营养品

      • 王雷
        王雷

        飞机对敌舰和空中飞行采取驱逐行动形成武力对峙

      热点图片
      拼命载入中...