Promise 概念的理解

发表时间

《Puppteer 实现 web 自动测试》 一文里,可以看出来如果 Puppteer 脚本用 async/await 和 promise的一些写法,会让脚本非常易懂,而且符合我们人工操作浏览器的习惯。所以为了写好 Puppteer 脚本,需要先对 async/await 的概念有所了解。


一个比方

你和老王打赌:明天是否下雨。如果你赢了,老王给你10个亿;如果你输了,你给老王10块钱。


如果用一块展板描述这个赌局,可以是这样:

【明日下雨】 老王赌局
——————————
赢: +10亿
输: -10元

转眼跟小王打赌:

【明日下雨】 小王赌局
——————————
赢: 被请KFC
输: 请KFC

由上可见, 赌局赌注 是无关的。比如,同样是明天下雨,另一场赌局可能如下:

由此得到【规则1】

规则1:输赢规则和赌注无关,可以分离

当赌局完成后,只要出现了一种情况,那么另一种情况必然不会同时发生,比如不可能既下雨又不下雨。由此得到【规则2】

规则2:只能有一种结果出现。

如果你和老王商量好了:如果明天下雨,老王付你10块钱。到了第二天果然下雨,老王反悔了,想修改输赢规则,你一定是不同意的,这就叫买定离手。由此得到【规则3】

规则3:输赢结果一旦出现,则不能更改。

如何描述

用一段伪代码描述上面的下雨赌局,可以这么写

赌局(赢,输){
   到明天()
    如果下雨{
        赢()
    }如果没下{
        输()
    }
}

到明天 函数可以替换成 抛硬币(), 或者是 参加考试(),这种负责产生结果的函数,可以称之为“生产者”。

赢 函数 可以是 {得5元} ,或者是 {被请KFC},这种针对结果的处理方案,可以称之为“消费者”。

这种“生产者”和“消费者”分离的状态,对应了上面的 规则 1

而赌局本身,既不产生结果,也不消费结果,只是将无关的二者结合在一起,并进行一次。将赌局抽象出来,就是 Promise 。

生产者(抛硬币)→ Promise → 消费者(赌注)

所以 Promise 可以理解为一个中介(Proxy),一个 Promise 对象用下面代码生成:

let promise = new Promise(function(resolve, reject) {
  // 生产者代码
});

promise 对象生成时,将执行 生产者代码,并生产出结果。Promise 接收一个函数作为参数,这个函数的两个参数分别对应成功和失败的消费者函数,消费前面生产出的结果。

生产者代码在得出结果后,应该根据结果的不同,调用 对应的消费者函数(成功则调用 resolve,失败则调用 reject),同时将结果作为消费者函数的参数,从 promise 对象中传递出去。

举个例子,最简单的生产者代码,恐怕就是“什么也不做”了,直接判定为成功,只有resolve一种结果。

let promise = new Promise(function(resolve, reject) {
  resolve("done")
});

这段代码执行后,对象 promise的状态就固定为成功(fulfilled),而且不能改变。当然也可以直接判定失败:

let promise = new Promise(function(resolve, reject) {
  reject("lose")
});

这段代码执行后,对象 promise的状态就固定为失败(rejected)

Await

生产者代码 除了生产成功或者失败的结果,往往还有其他类型的结果输出,比如文件内容、或者新的对象实例,等等。所以需要通过 resolve 函数将输出的结果传递出来。 await 可以在外面接纳这个结果。

Promise → resolve → await

比如,可以这么使用 await

let promise = new Promise(function(resolve, reject) {
  resolve("done")
});

  let result = await promise; 

  console.log(result);  // "done"

这个例子里,我们可以从控制台里看到 “done” 的输出, await 一直等待 promise 的成功结果,一旦等到,就将 resolve 的参数返回给 result 变量

Async

要想使用 await 关键字,还必须声明 await 所在的函数为 async,用法很简单,只要在 function 前面加上 async 就行。

async function(){ await … }

async function(){
  let promise = new Promise(function(resolve, reject) {
    resolve("done")
  });

  let result = await promise; 

  console.log(result);  // "done"
}

函数声明之前加上 async 后, 即使不用明确的声明 return,函数总会隐含的返回一个 Promise。如果明确的写明 return 一个值,函数也仍然返回一个 Promise,然后使这个 Promise 成功 resolve 那个值。比如下面的例子:

async function(){
  //其他代码

  return 1
}

等效于

async function(){
  //其他代码

  return Promise.resolve(1)
}

这个返回值是可以被 await 等待得到的。

理解了上面的内容,我们就可以继续用 puppeteer 编写自动脚本了

本页面内容采用 署名协议 CC-BY 授权。欢迎转载,请保留原文链接


分类

相关文章