前端面试送命题(二)-callback,promise,generator,async-await

时间:2022-03-18 23:44:25

前言

本篇文章适合前端架构师,或者进阶的前端开发人员;我在面试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&num;中关于协变性和逆变性(又叫抗变)帮助理解

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

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

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

  4. Promise&comma; Generator&comma; async&sol;await的渐进理解

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

  5. Callback&comma; Promise和Async&sol;Await的对比

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

  6. js中异步方案比较完整版&lpar;callback&comma;promise&comma;generator&comma;async&rpar;

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

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

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

  8. callback vs async&period;js vs promise vs async &sol; await

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

  9. Promise及Async&sol;Await

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

随机推荐

  1. zookeeper原理解析-服务器端处理流程

    1)处理器链 这部分内容我们主要讲解zookeeper请求在zookeeper server端的处理流程,对于不同角色的zookeeper具有不同的处理流程, ZookeepeerServer的sta ...

  2. django学习&lt&semi;二&gt&semi;:连接数据库

    发现假如没有很迫切的实际需求或者外界的压力的话,我这种人就很容易偷懒,之前看了一篇比较权威的谈django的文章,里面列举支持的数据库只有四种, 可是我熟悉的数据库只有sqlserver,然后就又怠工 ...

  3. Console&period;log,Window&period;alert,Document&period;write三者区别

    1.Console.log不会阻断程序继续进行,在控制台可以看到测试结果. 2.Window.alert弹出框会阻断程序运行,在弹出框可以看到测试结果. 3.Document.write不会阻断程序继 ...

  4. python之rabbitMQ篇

    一.RabbitMQ安装 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统,它遵循Mozilla Pulic License开源协议. MQ全称为Message Queue,消息队列 ...

  5. Flex ObjectHandles 构建绘图程序&excl;

    模型 主画布组件:com/components/graph/GraphContainer.mxml <?xml version="1.0" encoding="ut ...

  6. &lpar;转&rpar;ReSharper 配置及用法

    1:安装后,Resharper会用他自己的英文智能提示,替换掉 vs2010的智能提示,所以我们要换回到vs2010的智能提示 2:快捷键.是使用vs2010的快捷键还是使用 Resharper的快捷 ...

  7. AJAX异步提交,浏览器总跳出下载界面

    问题: 我在写一个网页的“用户登录”部分时,要将用户名和密码传到后端验证,想在前端用了AJAX异步提交功能,将 用户名密码传到后端,然后后端返回验证结果.但AJAX写好后每次刷新网页都会跳出下载窗口, ...

  8. 如何在CentOS 7上部署Google BBR【搬运、机翻】

    如何在CentOS 7上部署Google BBR 本文章搬运自 https://www.vultr.com/docs/how-to-deploy-google-bbr-on-centos-7 [注:文 ...

  9. golang&colon;使用timingwheel进行大量ticker的优化

    Ticker 最近的项目用go实现的服务器需要挂载大量的socket连接.如何判断连接是否还存活就是我们需要考虑的一个问题了. 通常情况下面,socket如果被客户端正常close,服务器是能检测到的 ...

  10. Linux 自动化部署DNS服务器

    Linux 自动化部署DNS服务器 1.首先配置主DNS服务器的IP地址,DNS地址一个写主dns的IP地址,一个写从dns的地址,这里也可以不写,在测试的时候在/etc/resolv.conf中添加 ...