前端面试送命题(二)-callback,promise,generator,async-await
前言
本篇文章适合前端架构师,或者进阶的前端开发人员;我在面试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的更多相关文章
- 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
- JQuery选择器大全 前端面试送命题:面试题篇 对IOC和DI的通俗理解 c#中关于协变性和逆变性(又叫抗变)帮助理解
JQuery选择器大全 jQuery 的选择器可谓之强大无比,这里简单地总结一下常用的元素查找方法 $("#myELement") 选择id值等于myElement的元素 ...
- 一个例子读懂 JS 异步编程: Callback / Promise / Generator / Async
JS异步编程实践理解 回顾JS异步编程方法的发展,主要有以下几种方式: Callback Promise Generator Async 需求 显示购物车商品列表的页面,用户可以勾选想要删除商品(单选 ...
- Promise, Generator, async/await的渐进理解
作为前端开发者的伙伴们,肯定对Promise,Generator,async/await非常熟悉不过了.Promise绝对是烂记于心,而async/await却让使大伙们感觉到爽(原来异步可以这么简单 ...
- Callback, Promise和Async/Await的对比
Callback, Promise和Async/Await的对比 Callback Hell getData1(function (data1) { console.log('我得到data1了') ...
- js中异步方案比较完整版(callback,promise,generator,async)
JS 异步已经告一段落了,这里来一波小总结 1. 回调函数(callback) setTimeout(() => { // callback 函数体 }, 1000) 缺点:回调地狱,不能用 t ...
- 前端面试送命题-JS三座大山
前言 本篇文章比较适合3年以上的前端工作者,JS三座大山分别指:原型与原型链,作用域及闭包,异步和单线程. 原型与原型链 说到原型,就不得不提一下构造函数,首先我们看下面一个简单的例子: functi ...
- callback vs async.js vs promise vs async / await
需求: A.依次读取 A|B|C 三个文件,如果有失败,则立即终止. B.同时读取 A|B|C 三个文件,如果有失败,则立即终止. 一.callback 需求A: let read = functio ...
- Promise及Async/Await
一.为什么有Async/Await? 我们都知道已经有了Promise的解决方案了,为什么还要ES7提出新的Async/Await标准呢? 答案其实也显而易见:Promise虽然跳出了异步嵌套的怪 ...
随机推荐
- leetcode-66.加一
leetcode-66.加一 题意 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个 ...
- python语言学习---3
第四天 1.set 持有一系列元素,这一点和 list 很像,但是set的元素没有重复,而且是无序的, 这点和 dict 的 key很像. (不信可以输出下试试 ~-~ )另外,其存储的对象必须不可变 ...
- DAY14(PYTHONS)生成器进阶
def average(): sum = 0 count = 0 avg = 0 while True: #循环 num = yield avg #遇到yield就停止,防止一开始除数为0导致崩溃 s ...
- mysql的连接
本文内容: mysql客户端连接服务端 断开连接 首发日期:2018-04-07 mysql客户端连接服务端: 连接服务端的命令基本语法是: mysql -h host -u user -p -P p ...
- Django基础笔记
1.准备工作 .虚拟环境设置 python3 pip install virtualenv python -m venv env(虚拟环境文件名) env\Scripts\activate pip i ...
- c/c++ static关键字
static关键字 1,static 成员变量 static 成员变量不随着对象的创建而开辟内存空间.也就是说,不管从哪个对象去看static成员变量,都是一样的. 2, static 成员方法 st ...
- 通用Logging框架设计
项目开发中,大家都会使用日志框架(LogBack, log4j , java.util.logging 等).下面来简单的了解一下日志框架的大体设计思路. 类图:
- 如何设置可以避免php代码中的中文在浏览器中成为乱码?
其实很简单,只需要在代码开始的前面加上一条这样的语句就行: //这里面我的浏览器中的字符编码格式为utf-8,所以这里我设置为utf-8,如果你的浏览器中的默认编码不是这个,请选择浏览器默认的编码格式 ...
- Docker 从入门到实践(二)Docker 三个基本概念
一.Docker 的三个进本概念? 了解 Docker 的三个基本概念,就可以大致了解 Docker 的生命周期. 镜像(Image) 容器(Container) 仓库(Repository) 二.镜 ...
- 手动搭建Docker本地私有镜像仓库
实验环境:两个Centos7虚拟机,一个是Server,用作客户端,另一个是Registry,用作Docker私有镜像仓库. 基础配置 查看一下两台虚拟机的IP地址 Server的IP地址是192.1 ...