[译]ES6入门(第二部分)

原文戳这里

[译]ES6入门(第一部分)

[译]ES6入门(第三部分)

这篇文章的第一部分出现在这里。 我在那里介绍了一些有趣的功能:)

我将在这篇文章中介绍的主题包括:

1、Promises

2、Async / Await

Promises

Promise是ES6中的一个有用功能。它们用于进行异步操作,例如API请求,文件处理,下载图像等。

那么,什么是异步? (继续,如果你已经知道)

异步操作是需要一些时间才能完成的操作。

例如,假设您正在定义向服务器发出API请求的函数。该函数不会立即返回结果,因为从服务器获取响应需要几秒钟。

因此,如果您正在调用该函数并将其值(即)返回的结果分配给某个变量,那么它将是未定义的。因为Javascript不知道该函数正在处理一些异步操作。

那我们该如何处理呢?

让我们先谈谈一些历史。

在Promise之前,程序员习惯于定义回调。回调是Javascript中的常规函数,它在异步操作完成时执行。

例如,您定义了一个向服务器发出API请求的函数。然后你设置了一个回调函数,它将在我们从服务器获得响应时执行。

所以在上面的例子中,Javascript不会停止执行,直到我们从API获得响应。我们已经定义了一个函数(回调),它将在我们得到响应后执行。我想你明白了。

那么,Promise是什么?

Promise是有助于执行异步操作的对象。

从技术上讲,它们是表示异步操作完成的对象。 (如果你不明白,请继续往下阅读一会儿)

在解释如何定义Promise之前,我将解释Promise的生命周期。

在Promise中有三种状态:

1、挂起:在这种状态下,promise只是执行异步操作。例如,它正在向服务器发出一些API请求或从cdn下载一些图像。 从这个状态Promise可以转移到完成状态或拒绝状态

2、完成:如果Promise已达到此状态,则表示异步操作已完成,并且得到了输出的结果。例如,我们有了来自API的响应。

3、拒绝:如果Promise已达到此状态,则表示异步操作未成功,并且我们得到导致操作失败的错误。

好的..让我们看一些代码。

const apiCall = new Promise(function(resolve, reject) {
 // 异步操作在这里定义..
});

通过使用new关键字创建构造函数来定义Promise。 然后构造函数将有一个函数(我们称之为执行函数。)

异步操作在执行函数内定义。

请注意,执行函数有两个参数resolve和reject。

第一个参数resolve实际上是一个函数。 它在执行函数内部调用,它表示异步操作成功,我们得到了结果。 resolve函数有助于Promise从挂起状态转为完成状态。 希望你明白了。:)

像resolve一样,reject也是一个函数。 它也在执行函数内部调用,它表示异步操作不成功,我们遇到了错误。 reject函数有助于Promise从挂起状态转为拒绝状态。:)

const apiCall = new Promise(function(resolve, reject) {
 if ( API request to get some data ) {
  resolve("The request is successful and the response is "+ response);
 }
 else {
  reject("The request is not successful. The error is "+error);
 }
});

在上面的代码中,您可以看到我们在执行函数中完成了一些异步操作。 如果我们从服务器获得响应,则调用resolve函数。 如果有错误,则会使用错误消息调用reject函数。

我们已经完成了Promise。 让我们看看如何执行Promise并处理输出。

// 调用promise.
apiCall

就是这样。 结束了。 :) :)

开玩笑。 还没结束。

在上面的代码中,调用函数并执行promise(即执行函数)。 然后根据输出调用resolve或reject函数。

但是你可以看到我们没有处理promise中返回的输出。

例如,如果我们从API获得响应,那么我们必须处理响应。 或者如果我们得到错误,我们需要正确处理它。

那我们该如何处理呢?

我们使用处理器来获取promise的输出。

处理器是在某些事件发生时执行的函数,例如单击按钮,移动光标等。

因此,当resolve函数被调用或reject函数被调用时,我们可以使用处理器来处理。

简单。:)

我们来看一些代码

// 调用promise,并使用handlers.
apiCall.then(function(x) {console.log(x); })

在上面的代码中,我们将一个处理器then附加到promise。处理器then有一个函数参数。函数参数本身有一个参数x。

发生了什么事?

当在promise内调用resolve函数时,处理器then执行其函数参数。

我会再解释一次。

处理器then监听resolve函数被调用时的事件。 因此,当调用resolve函数时,处理器then执行其函数参数。

apiCall.then(function(x) {console.log(x); })
// 输出
The request is successful and the response is {name: "Jon Snow"}

同样,还有另一个处理器catch。

Catch监听reject函数。

Catch函数在reject函数被调用时执行其函数参数。

apiCall.then(function(x) {console.log(x); }).catch(function(x) {console.log(x); })
// 假设这个请求没有成功 (在promise中reject函数被调用. )
输出:
The request is not successful

我想你明白了。

上面的代码不太可读。 所以让我们尝试重构它。

apiCall
.then(function(x) {
 console.log(x); 
})
.catch(function(x) {
 console.log(x);
}) 

啊......现在可读了。 大多数程序员都这样写。

好吧..所以我觉得你已经走了很长的路。

我们来回顾一下。

1、使用带有函数参数的new关键字定义Promise。 然后函数本身有两个函数参数resolve和reject。

2、操作成功时应调用resolve函数。

3、操作失败时应调用reject函数。

4、处理器then监控resolve函数。

5、处理器catch监控reject函数。

6、确保代码的可读性:) :)

这是可运行的示例。 如果您不熟悉,请练习。

var ApiCall = new Promise(function(resolve, reject) {
  
  var request = new XMLHttpRequest();
  request.open('GET', 'https://api.github.com/users/srebalaji');

  request.onload = function() {
    if (request.status == 200) {
      
      resolve(request.response);
    } else {
      reject(Error(request.statusText));
    }
  }

  request.send();
});

ApiCall
.then(function(x) {
  document.getElementById('response').innerHTML = x;
})
.catch(function(x) {
    document.getElementById('response').innerHTML = x;
})

希望你能理解这个例子。 它直截了当。

Async / Await

如果您了解Promises,那么Async / Await非常简单。 如果你没有弄明白Promises,Async / Await可以帮助你理解它。 也许你也可以彻底地躲开Promises。:)

Async

Async关键字使任何函数只返回promises。

例如,请看以下代码

async function hello() {
 return "Hello Promise..!"
}

函数hello将返回一个promise。

上面的代码相当于下面的代码。

function hello() {
 return new Promise(function(resolve, reject) {
 // executor function body
 });
}

非常简单是吧?

另外一个例子:

async function hello(a, b) {
 if (a < b) {
  return "Greater";
 }
 else {
  return new Error("Not Greater");
 }
}
hello(14, 10)
.then(function(x) {
 console.log("Good..! " + x); 
})
.catch(function(x) {
 console.log("Oops..! " + x); 
})
输出:
Oops..! Not Greater. 
// 如果你调用 hello(4, 10) 你会得到 "Good..! Greater"

在上面的代码中,我们定义了一个async函数并返回了一些值或返回了一些错误。

如果要在async函数中返回一些值,则它等同于调用resolve函数。

如果通过使用'new'调用错误构造函数(即)返回一些错误,则它等同于reject函数。

不要忘记async函数将返回一个promise。 当然,你也可以在async函数中调用resolve和reject函数。

让我们看看它是如何工作的。

async function Max(a, b) {
 if (a > b) {
  return Promise.resolve("Success");
 }
 else {
  return Promise.reject("Error");
 }
}
Max(4, 10)
.then(function(x) {
 console.log("Good " + x); 
})
.catch(function(x) {
 console.log("Oops " + x); 
});
输出:
Oops Error
// 如果调用 Max(14, 10) 我们会得到 "Good Success" :)

Await

顾名思义,它使Javascript等到操作完成。 假设您正在使用await关键字发出API请求。 它使Javascript等待,直到您从端点获得响应。 然后它恢复执行。

好的..让我们走得更远

Await只能在异步函数中使用。 它在异步功能之外不起作用

我们来看一个例子吧

async function hello() {
 let response = await fetch('https://api.github.com/');
 // 上面一行从给定的API终端获取响应
 return response;
}
hello()
.then(function(x) {
 console.log(x); 
});
...
...
输出:
Response from the API.

在上面的代码中,您可以看到我们在从API获取响应时使用了await。

获取操作可能需要几秒钟才能获得响应,直到获取到响应,执行将暂停并稍后恢复。

请注意,await操作仅停止hello函数内的执行。 hello函数外的其余代码不会受到影响。 执行在函数外部继续。 当我们得到响应时,执行内部函数参数。

希望你明白了。

我们来看一个例子

function getResponse() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve("Response from API. Executed after 5 secs");
    }, 5000);
  });
}

async function hello() {
  let response = await getResponse();
  return response;
}

hello()
  .then(function(x) {
    console.log(x);
  })
  .catch(function(x) {
    console.log(x);
  });
console.log("Im executed before getResponse()");

在上面的示例中,您可以看到我们对getResponse函数使用了await。 并且getResponse将在5秒后返回输出或错误。 因此,在此之前,执行将暂停,然后返回响应。

让我们看一些实时的例子

function getResponse(url) {
    return new Promise(function(success, failure) {
  var request = new XMLHttpRequest();
    request.open('GET', url);
    
  request.onload = function() {
    if (request.status == 200) {
      return success(request.response);
    } else {
      return failure("Error in processing..!" + request.status);
    }
  }
  request.onerror = function() {
    return failure("Error in processing ");
  }
  request.send();
  });
}

function getUsername(response) {
  response = JSON.parse(response);
  return response["login"];
}

function makeUsernameCaps(name) {
    return new Promise(function(success, failure) {
    // Let's assume it takes 3secs to make the username caps :) 
    setTimeout(function() {
    success(name.toUpperCase());
    }, 3000)
  });
}
async function apiCall(url) {
  let response = await getResponse(url); 
  let username = await getUsername(response);
  let username_in_caps = await makeUsernameCaps(username);
  return username_in_caps;
}

apiCall("https://api.github.com/users/srebalaji")
.then(function(x) {
    console.log(x);
})
.catch(function(x) {
    console.log("Error - "+x);
});

在上面的例子中,您可以看到我们已经使用了多个await。 因此,对于每个await, 程序停止执行,直到收到响应然后恢复。

在示例中尝试使用一些无效网址。 您可以看到引发错误。

async函数中的错误处理非常简单。 如果在async函数内引发错误,或者在async函数中使用await调用的其他函数内引发错误,则会调用reject函数。 简单。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • 异步编程对JavaScript语言太重要。Javascript语言的执行环境是“单线程”的,如果没有异步编程,根本...
    呼呼哥阅读 7,302评论 5 22
  • 弄懂js异步 讲异步之前,我们必须掌握一个基础知识-event-loop。 我们知道JavaScript的一大特点...
    DCbryant阅读 2,708评论 0 5
  • Promise 对象 Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函...
    neromous阅读 8,703评论 1 56
  • 其实夏天在小米的世界里,是和花儿一样,冰凉可爱的。 一部分原因,是R·yBradbury的短篇小说中的一段描写:“...
    七分秋色阅读 402评论 0 1
  • 闲逸的梦醒了 我窥见瓶枝的苍白 于是 在静默的夜里 揉碎自己 就这样魂归泥土 寻回血脉根系 我知道郁结着怎样的期待...
    袭瞬阅读 190评论 2 1