blog icon indicating copy to clipboard operation
blog copied to clipboard

Promise--一诺千金

Open zwhu opened this issue 8 years ago • 2 comments

image

TL;DR 本文是对 Promise 一些概念点的归纳和对 Promise 在解决什么问题的思考。 并不会介绍 Promise 的 Api。

一直想写一篇关于 Promise 的文章,一直没有动笔,觉得自己对 Promise 是一知半解,连记录想法的勇气都没有。前几天刚好在看 Dr. Axel Rauschmayer 的『 Exploring ES6 』 这本书的时候,看到关于 Promise 的章节,仔细读了一遍,动手实现了简易版的 Promise 一遍,印证其它的资料又回味了一遍,这才敢开始动手写这篇文章。

要知道 Promise 哪些知识点

const p = new Promise(
    function (resolve, reject) { // (A)
        ···
        if (···) {
            resolve(value); // success
        } else {
            reject(reason); // failure
        }
    })
  1. A 行的函数被称为 executor
  2. 当实例化一个 Promise 的时候,executor 总是「立即执行」的
  3. Promises 总是异步执行的。在 then 的消耗 Promise value 时候,会把 then 的参数放到任务队列中,等待执行。
  4. Promise 中的状态进入稳定态(settled)的时候,Promise 的值便不会再发生变化,这就是 Promise 的名称由来:承诺。
// executor 立即执行的验证
new Promise( (res) => {
  console.log(1)
  setTimeout(() => console.log(3), 1000)
})
console.log(2)
// ------> 1
// ------> 2
// ------> 3

// then 的参数是异步调用的验证
new Promise( (res) => {
  res(2)
}).then(v=> console.log(v))
console.log(1)
// ------> 1
// ------> 2


// 当在 executor 中通过调用 res 使状态稳定之后,不管调用多少次 res,值都不会再发生变化
new Promise( (res) => {
  res(1)
  res(2)
}).then(v=> console.log(v))
// ------> 1

Promise -- 一诺千金

Promise 的优点是什么?我看了很多文章在介绍 Promise 的时候都会提到回调噩梦(Callback Hell)。然而我觉得 Promise 并没有简单的解决回调噩梦的问题,写 then 往往比写 callback 更恶心。

在我看来,Promise 提供了控制反转的机会。

假设有下面这样一个函数,10 秒后调用传入的 fn。这是一个你的同事提供给你的独立文件。

// foo.js
function foo(fn) {
  setTimeout(fn, 1000*10)
}

module.exports = foo

你在写一个 10 秒之后打印 log 的业务:

var foo = require('foo')

foo(()=> console.log('hello,world!!'))

然而很不幸,你的同事离职,他的代码被交给一个很笨的新同事维护,新同事维护这个代码的时候,不小心复制了一行代码:

// foo.js
function foo(fn) {
  setTimeout(fn, 1000*10)
  setTimeout(fn, 1000*10)
}

module.exports = foo

这时每次调用 foo 的时候,都会写两遍日志,不到 1 天服务器的硬盘就被撑爆了,用户就不能访问网页了,接着用户就流失了,公司倒闭了,你就被失业了,想想都是很可怕的事情。这些都是因为你把你的函数交给你的同事调用并且无条件信任他。

然而 Promise 会怎样做?


// foo.js
function foo() {
  return new Promise((res) => {
    setTimeout(res, 1000*2)
  })
}

module.exports = foo

// main.js

var foo = require('foo')

foo().then(()=> console.log('hello,world!!'))

那个笨同事又干了同样的蠢事,这次他复制了三行:


// foo.js
function foo() {
  return new Promise((res) => {
    setTimeout(res, 1000*10)
    setTimeout(res, 1000*10)
    setTimeout(res, 1000*10)
  })
}

module.exports = foo

然而这次让我失业的行为并没有得逞,因为当 Promise 的状态稳定之后,值就不会再改变,不管调用多少次 reslove 方法都是同样的效果。Callback 会把你做的事情的权限交出去,你不再对你的函数有控制权,而 Promise 是在等状态稳定之后才会再去执行你自己的函数,你对此函数拥有控制权。

不过说到底,都没有绝对的信任,也说不定有人会把 Promise 的 then 实现 hack 了,而这种恶意做法的成本要比他不小心多复制一行代码的成本要高得多。


引用:

Exploring ES6

zwhu avatar May 23 '16 17:05 zwhu

老师您好!我有个问题

代码在chrome50.0.2661.102 osx10.11.5下运行

new Promise( (res) => { console.log(2) setTimeout(() => console.log(3), 1000) }); console.log(1)

输出

2016-05-26 21:56:02.660 VM760:2 2

2016-05-26 21:56:02.661 VM760:4 1

undefined

2016-05-26 21:56:03.662 VM760:3 3

holoto avatar May 26 '16 14:05 holoto

@holoto 我不是老师 - -

你的运行结果是对的,那里是我写错了 - -,但是结论是正确的。哈哈。

zwhu avatar May 26 '16 16:05 zwhu