前言

本篇文章适合前端架构师,或者进阶的前端开发人员;我在面试vmware前端架构师的时候,被问到关于callback,promise,generator,async-await的问题。

首先我们回顾一下javascript异步的发展历程。

ES6 以前:

  回调函数(callback);nodejs express 中常用,ajax中常用。

ES6:

  promise对象; nodejs最早有bluebird promise的雏形,axios中常用。

  generator函数;nodejs koa框架使用率很高。

ES7:

  async/await语法; 当前最常用的异步语法,nodejs koa2 完全使用该语法。

回调函数callback

回调函数实际就是一个参数;将一个函数当做参数传到另一个函数里,当那个函数执行完后,再执行传进去的这个函数;这个过程就叫做回调。

回调字面也好理解,就是先处理本体函数,再处理回调的函数,举个例子,方便大家理解。

function A(callback){
console.log("我是主体函数");
callback();
} function B(){
console.log("我是回调函数");
} A(B);
/*输出结果
我是主体函数
我是回调函数
*/

上面的例子很好理解,首先执行主体函数A,打印结果:我是主题函数;然后执行回调函数callback 也就是B,打印结果:我是回调函数。

promise对象

promise 对象用于一个异步操作的最终完成(或最终失败)及其结果的表示。

简单地说就是处理一个异步请求。我们经常会做些断言,如果我赢了你就嫁给我,如果输了我就嫁给你之类的断言。这就是promise的中文含义:断言,一个成功,一个失败。

举个例子,方便大家理解:

promise构造函数的参数是一个函数,我们把它称为处理器函数,处理器函数接收两个函数reslove和reject作为其参数,当异步操作顺利执行则执行reslove函数, 当异步操作中发生异常时,则执行reject函数。通过resolve传入得的值,可以在then方法中获取到,通过reject传入的值可以在chatch方法中获取到。

​因为then和catch都返回一个相同的promise对象,所以可以进行链式调用。

function readFileByPromise("a.txt"){
//显示返回一个promise对象
return new Promise((resolve,reject)=>{
fs.readFile(path,"utf8",function(err,data){
if(err)
reject(err);
else
resolve(data);
})
})
}
//书写方式二
readFileByPromise("a.txt").then( data =>{
//打印文件中的内容
console.log(data);
}).catch( error =>{
//抛出异常,
console.log(error);
})

generator函数

ES6的新特性generator函数(面试的时候挂在这里),中文译为生成器,在以前一个函数中的代码要么被调用,要么不被调用,还不存在能暂停的情况,generator让代码暂停成待执行,定义一个生成器很简单,在函数名前加个*号,使用上也与普通函数有区别。

举个例子,方便大家理解:

function *Calculate(a,b){
let sum=a+b;
console.log(sum);
let sub=a-b;
console.log(sub);
}

上面便是一个简单的generator声明例子。

generator函数不能直接调用,直接调用generator函数会返回一个对象,只有调用该对象的next()方法才能执行函数里的代码。

let gen=Calculate(2,7);

执行该函数:

gen.next();
/*打印
9
-5
*/

其实单独介绍generator并没有太大的价值,要配合key yield,才能真正发挥generator的价值。yield能将生Generator函数的代码逻辑分割成多个部分,下面改写上面的生成器函数。

function *Calculate(a,b){
let sum=a+b;
yield console.log(sum);
let sub=a-b;
yield console.log(sub);
}
let gen=Calculate(2,7);
gen.next();
/*输出
9*/

可以看到这段代码执行到第一个yield处就停止了,如果要让里边所有的代码都执行完就得反复调用next()方法

let gen=Calculate(2,7);
gen.next();
gen.next();
/*输出
9
-5*/

在用一个例子,来说明generator函数与回调函数的区别:

回调函数:

fs.readFile("a.txt",(err,data)=>{
if(!err){
console.log(data);
fs.readFile("b.txt",(err,data)=>{
if(!err)
console.log(data);
})
}
})

这是一个典型的回调嵌套,过多的回调嵌套造成代码的可读性和可维护性大大降低,形成了令人深恶痛绝的回调地狱,试想如果有一天让你按顺序读取10个文件,那就得嵌套10层,再或者需求变更,读取顺序要变了先读b.txt,再度a.txt那改来真的不要太爽。

generator函数:

function readFile(path) {
fs.readFile(path,"utf8",function(err,data){
it.next(data);
})
} function *main() {
var result1 = yield readFile("a.txt");
console.log(result1); var result2 = yield readFile("b.txt");
console.log(result2); var result3 = yield readFile("c.txt");
console.log(result3);
} var it = main();
it.next();

generator函数的强大在于允许你通过一些实现细节来将异步过程隐藏起来,依然使代码保持一个单线程、同步语法的代码风格。这样的语法使得我们能够很自然的方式表达我们程序的步骤/语句流程,而不需要同时去操作一些异步的语法格式。

async-await

async函数返回一个promise对象,如果在async函数中返回一个直接量,async会通过Promise.resolve封装成Promise对象。
我们可以通过调用promise对象的then方法,获取这个直接量。

async function test(){
return "Hello World";
} var result=test();
console.log(result);
//打印Promise { 'Hello World' }

那如过async函数不返回值,又会是怎么样呢?

async function test(){

}
var result=test();
console.log(result);
//打印Promise { undefined }

await会暂停当前async的执行,await会阻塞代码的执行,直到await后的表达式处理完成,代码才能继续往下执行。
await后的表达式既可以是一个Promise对象,也可以是任何要等待的值。
如果await等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

上边你看到阻塞一词,不要惊慌,async/await只是一种语法糖,代码执行与多个callback嵌套调用没有区别,本质并不是同步代码,它只是让你思考代码逻辑的时候能够以同步的思维去思考,避开回调地狱,简而言之-async/await是以同步的思维去写异步的代码,所以async/await并不会影响node的并发数,大家可以大胆的应用到项目中去!

如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。

举个例子,方便大家理解:

function A() {
return "Hello ";
} async function B(){
return "World";
} async function C(){
//等待一个字符串
var s1=await A();
//等待一个promise对象,await的返回值是promise对象resolve的值,也就是"World"
var s2=await B();
console.log(s1+s2);
} C();
//打印"Hello World"

前端面试送命题(二)-callback,promise,generator,async-await的更多相关文章

  1. 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制

    [原创]分布式之数据库和缓存双写一致性方案解析(三)   正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...

  2. JQuery选择器大全 前端面试送命题:面试题篇 对IOC和DI的通俗理解 c#中关于协变性和逆变性(又叫抗变)帮助理解

    JQuery选择器大全   jQuery 的选择器可谓之强大无比,这里简单地总结一下常用的元素查找方法 $("#myELement")    选择id值等于myElement的元素 ...

  3. 一个例子读懂 JS 异步编程: Callback / Promise / Generator / Async

    JS异步编程实践理解 回顾JS异步编程方法的发展,主要有以下几种方式: Callback Promise Generator Async 需求 显示购物车商品列表的页面,用户可以勾选想要删除商品(单选 ...

  4. Promise, Generator, async/await的渐进理解

    作为前端开发者的伙伴们,肯定对Promise,Generator,async/await非常熟悉不过了.Promise绝对是烂记于心,而async/await却让使大伙们感觉到爽(原来异步可以这么简单 ...

  5. Callback, Promise和Async/Await的对比

    Callback, Promise和Async/Await的对比 Callback Hell getData1(function (data1) { console.log('我得到data1了') ...

  6. js中异步方案比较完整版(callback,promise,generator,async)

    JS 异步已经告一段落了,这里来一波小总结 1. 回调函数(callback) setTimeout(() => { // callback 函数体 }, 1000) 缺点:回调地狱,不能用 t ...

  7. 前端面试送命题-JS三座大山

    前言 本篇文章比较适合3年以上的前端工作者,JS三座大山分别指:原型与原型链,作用域及闭包,异步和单线程. 原型与原型链 说到原型,就不得不提一下构造函数,首先我们看下面一个简单的例子: functi ...

  8. callback vs async.js vs promise vs async / await

    需求: A.依次读取 A|B|C 三个文件,如果有失败,则立即终止. B.同时读取 A|B|C 三个文件,如果有失败,则立即终止. 一.callback 需求A: let read = functio ...

  9. Promise及Async/Await

      一.为什么有Async/Await? 我们都知道已经有了Promise的解决方案了,为什么还要ES7提出新的Async/Await标准呢? 答案其实也显而易见:Promise虽然跳出了异步嵌套的怪 ...

随机推荐

  1. Javac编译原理 《深入分析java web 技术内幕》第四章

    javac编译的四个主要的流程: 词法分析器:将源码转换为Token流 将源代码划分成一个个Token(找出java语言中的关键字) 语法分析器:将Token流转化为语法树 将上述的一个个Token组 ...

  2. mysql之代码执行结构

    本文内容: 什么是代码执行结构 顺序结构 分支结构 循环结构 首发日期:2018-04-18 什么是代码执行结构: 这里所说的代码执行结构就是多条sql语句的执行顺序. 代码执行结构主要用于触发器.存 ...

  3. HashMap和Hashtable的同和不同(详细比较)

    一.综述 可以直接根据hashcode值判断两个对象是否相等吗?肯定是不可以的,因为不同的对象可能会生成相同的hashcode值.虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据h ...

  4. The JSP specification requires that an attribute name is

    把另一个博客内容迁移到这里 七月 10, 2016 10:23:12 上午 org.apache.catalina.core.ApplicationDispatcher invoke 严重: Serv ...

  5. 【MM系列】SAP的库存管理

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP的库存管理   前言部分 库存 ...

  6. java 一个实例

     this 代替

  7. 学习flying logic

    之前在知乎上结识的朋友吴笛,他的qq空间里分享了  flying logic的一些用途,我想到可以规划和团队的目标,这点让我感到很兴奋,分享学习这个软件. 学习之前,我应当把软件中的单词学明白.现在就 ...

  8. June 18. 2018, Week 25th. Monday

    Health and cheerfulness naturally beget each other. 安康喜乐,相生相成. From Joseph Addison. Good health is a ...

  9. vue methods 中方法的相互调用

    vue在同一个组件内:方法之间经常需要互相调用. methods中的一个方法如何调用methods中的另外一个方法呢? 可以在调用的时候使用  this.$options.methods.test2( ...

  10. [2] TensorFlow 向前传播算法(forward-propagation)与反向传播算法(back-propagation)

    TensorFlow Playground http://playground.tensorflow.org 帮助更好的理解,游乐场Playground可以实现可视化训练过程的工具 TensorFlo ...