前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >像写作一样去写代码,如何把异步的形式改写成同步的形式

像写作一样去写代码,如何把异步的形式改写成同步的形式

作者头像
mixlab
发布2018-12-26 15:52:07
7160
发布2018-12-26 15:52:07
举报

写代码的时候,碰到一大堆的缩进、花括号是不是特别头疼?为什么会有这么多的标点符号,还有各种技术概念?能不能像写作一样,自由得书写?从形式上,代码比文章多的是格式,格式代表了对应的技术原理。文本分享一则关于「 同步 、异步、阻塞、非阻塞 」的技术概念,结合Javascript中的图片加载,介绍如何把异步的形式改写成同步的形式,更加优雅的书写我们的代码。

def CodeFun( ):

先来看这么一个故事:

领导M需要准备一份年终总结的PPT,

他把这件事安排给了下属L

故事1

领导M非常不放心L,

于是决定在L边上陪着他把PPT做完

技术原理::「 同步阻塞 」

旁白::这领导太低效了,自己动手不行吗?

故事2

M安排L做PPT后,

跑去会议室开会,

并时不时到下属L的工位前看看PPT做完没

技术原理::「 同步非阻塞 」

旁白::这是大部分领导的做法(显得自己很忙)

故事3

M在交代PPT任务时,

特定嘱咐L,

做完PPT要主动来找他。

但是M还是不放心,

决定等在L边上,

陪着他做PPT

技术原理::「 异步阻塞 」

旁白::有这样的下属,也是够操心的。

故事4

M在交代PPT任务时,

特定嘱咐L,

做完PPT要主动来找他。

此时,

M决定全权交给L负责,

自己继续在会议室开会

技术原理::「 异步非阻塞 」

旁白::下属L发挥自己的主动性,把PPT完美完成,领导M也完成了会议。

所谓同步异步,只是对于L而言:

L做完PPT后沉默不语,叫 「 同步 」;

L做完PPT主动汇报,叫「 异步 」。

「 同步 」 的情况下,M得自己主动去询问做完PPT没。

「 异步 」 的情况下,M可以忙自己的事,L做完PPT会主动汇报。

所谓阻塞非阻塞,仅仅对于M而言:

「 阻塞 」的情况下, M陪着L做PPT。

「 非阻塞 」的情况下,M去会议室开会。

显然,「 异步+非阻塞 」是最高效的。

这就是同步、异步、阻塞、非阻塞的概念的通俗理解。回到代码写作上,我们实际写代码的时候,会比较习惯一种「 线性思维 」的方式,这种方式有点类似于做数学证明题的过程:

因为等边△ABC

所以∠A=∠B=60度

又PE⊥AC

所以∠AEP是直角

所以∠APE=30度

在△PBQ中

∠B=60度,∠Q=28度

所以∠QPB=92度

所以∠EPD=180-92-30=58度

一行行的书写方式,逻辑性非常强,简单明了的因果关系 ,这是一种典型的线性思维。下面举一个Javascript的例子。初学JS的同学,为了把图片绘制到canvas上,一般会这么写:

代码语言:javascript
复制
var img=.....

....

ctx.drawImage(img,0,0);

我们初学的时候,习惯一行行的书写方式,把图片数据存储在一个变量img里,然后再调用绘图命令使用img。

我们可以在浏览器中打开「 开发者工具 」,在console面板中进行实验:

代码语言:javascript
复制
var img=new Image();

img.src="https://images.unsplash.com/photo-1543363951-ec6198f35a38?auto=format&fit=crop&w=100&q=30";

var canvas=document.createElement("canvas");

var ctx=canvas.getContext("2d");

ctx.drawImage(img,0,0);

document.body.innerHTML='';

document.body.appendChild(canvas);

运行下,如果按照以上的写法,经常会出现图片绘制不出来的情况,因为图片是「 异步 」加载的。这个时候,我们需要把代码改写下:

代码语言:javascript
复制
var img=new Image();

img.src="https://images.unsplash.com/photo-1543363951-ec6198f35a38?auto=format&fit=crop&w=100&q=30";


img.onload=function(){

    var canvas=document.createElement("canvas");

    var ctx=canvas.getContext("2d");

    ctx.drawImage(img,0,0);

    document.body.innerHTML='';

    document.body.appendChild(canvas);

};

代码开始有了缩进,我们需要了解「 作用域 」的概念,我们继续把图片加载写成一个函数:

代码语言:javascript
复制
function loadImg(_url,_callback){

  var img=new Image();

  img.src=_url;

  img.onload=function(){

    _callback(img);

  };

};

加载一张图片:

代码语言:javascript
复制
loadImg("http://xxxx",function(img){

  ...

});

如果是多张图片加载呢?

代码语言:javascript
复制
loadImg("http://xx1",function(img){

  loadImg("http://xx2",function(img){

    loadImg("http://xx3",function(img){

      loadImg("http://xx4",function(img){

      ...

      });

    });  

  });

});

一层层的嵌套,写起来,看起来都非常难受?,为了解决这个问题,Promise出现了,loadImg可以写出then这种方式:

代码语言:javascript
复制
loadImg("http://xxx")

.then(function(img){

   ....

});

多张图片的加载,变成了这样:

代码语言:javascript
复制
loadImg("http://xxx1")

.then(function(img){

   ....

});



loadImg("http://xxx2")

.then(function(img){

   ....

});



loadImg("http://xxx3")

.then(function(img){

   ....

});

是不是开始有点一行行在书写代码的感觉?但是还是有一个缩进在碍事。以上例子真实可运行的代码可以参考如下:

代码语言:javascript
复制
function loadImg(_url){

    var img=new Image();

    img.src=_url;


    return new Promise(function(resolve, reject){

                img.onload=function(){

                    resolve(img);

                };

            });

};



loadImg("https://images.unsplash.com/photo-1543363951-ec6198f35a38?auto=format&fit=crop&w=100&q=30")

.then(function(img){

    var canvas=document.createElement("canvas");

    var ctx=canvas.getContext("2d");

    ctx.drawImage(img,0,0);

    document.body.innerHTML='';

    document.body.appendChild(canvas);

});

那能不能再简洁点呢?有个then在后面跟着看着也不太爽。而且我们在追求一行行的书写方式。这个时候就要用到 async/await 了,我们改写下:

代码语言:javascript
复制
async function loadImg(_url){

  var img=new Image();

  img.src=_url;

      return new Promise(function(resolve, reject){

                  img.onload=function(){

                      resolve(img);

                  };

              });

};



var img=await loadImg('https://images.unsplash.com/photo-1543363951-ec6198f35a38?auto=format&fit=crop&w=100&q=30');


var canvas=document.createElement("canvas");

var ctx=canvas.getContext("2d");

ctx.drawImage(img,0,0);

document.body.innerHTML='';

document.body.appendChild(canvas);

这下加载图片,可以用我们熟悉的“一行行”的写作方式了:

代码语言:javascript
复制
var img=await ...

....

ctx.drawImage(img,0,0);

return 优雅地写代码

关于MIXLAB

MIXLAB 无界社区是一所面向未来的实验室,它提倡“跨界创新,开放成长”的理念。

——跨界 开放 互助 学习 思维 创新。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 无界社区mixlab 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CLI 工具
云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档