0

javascripts中的promise

 1 year ago
source link: https://zhangrr.github.io/posts/20220524-javascripts_promise/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Javascripts中的promise

2022-05-24 3 分钟阅读

一、基本概念

1. 异步

所谓 " 异步 “,简单说就是一个任务分成两段, 先执行第一段, 然后转而执行其他任务去, 等做好了准备, 再回过头执行第二段。

比如, 有一个任务是读取文件进行处理, 任务的第一段是向操作系统发出请求, 要求读取文件。 然后, 程序执行其他任务, 等到操作系统返回文件,再接着执行任务的第二段( 处理文件)。 这种不连续的执行, 就叫做异步。

相应地, 连续的执行就叫做同步。 由于是连续执行, 不能插入其他任务, 所以操作系统从硬盘读取文件的这段时间, 程序只能干等着什么也做不了。

2. 回调函数

javascript 语言对异步编程的实现, 就是回调函数。 所谓回调函数, 就是把任务的第二段单独写在一个函数里面, 等到准备好了,继续执行的时候, 就直接调用这个函数。 它的英语名字 callback, 直译过来就是 " 回调 “。

读取文件进行处理, 是这样的,readfile 是异步的,readfileSync 是同步的。

fs.readfile('/etc/passwd', function(err, data) {
  if(err) throw err;
  console.log(data);
});
fallback

上面代码中, readfile 函数的第二个参数, 就是回调函数, 也就是任务的第二段。 等到操作系统返回了 / etc / passwd这个文件以后, 回调函数才会执行。

==一个有趣的问题是, 为什么 node.js 约定, 回调函数的第一个参数, 必须是错误对象 err( 如果没有错误, 该参数就是 null)? 原因是执行分成两段, 在这两段之间抛出的错误, 程序无法捕捉, 只能当作参数, 传入第二段。==

3. promise

“想像一下你是个小孩,你妈妈 promise 承诺你下星期给你一部新手机”

只有下周来临的时候,你才会知道你真的得到一部手机,或者是骗你玩的。

这就是 promise. 一个 promise 有三种状态:

  1. Pending: 待定,你不知道你是否能得到一部手机
  2. Resolved: 妈妈很高兴,你得到一部手机
  3. Rejected: 妈妈不高兴,你没有得到一部手机

状态图如下:

image-20220527222312367

语法很简单:

// promise syntax look like this
new Promise(function (resolve, reject) { ... } );

javascript

再看一下上面问题的解决方法:

首先确定 Mom 的状态是 unhappy,然后建立一个 Promise 来确定是否得到手机,最后用一个函数 askMom 来调用这个 Promise

var isMomHappy = false;

// Promise
var willIGetNewPhone = new Promise(
    function (resolve, reject) {
        if (isMomHappy) {
            var phone = {
                brand: 'Samsung',
                color: 'black'
            };
            resolve(phone); // resolved
        } else {
            var reason = new Error('mom is not happy');
            reject(reason); // rejected
        }

    }
);

var askMom = function () {
    willIGetNewPhone
        .then(function (fulfilled) {
            // yay, you got a new phone
            console.log(fulfilled);
             // output: { brand: 'Samsung', color: 'black' }
        })
        .catch(function (error) {
            // oops, mom didn't buy it
            console.log(error.message);
             // output: 'mom is not happy'
        });
};

askMom();
fallback

很有点意思吧。抽象了,那就实际点。

javascripts 中的 fetch 函数返回的就是一个 promise,promise 随后的 then函数,同样也是promise,两个参数,resolve 和 reject ,缺省一个参数呢就是 resolve

    fetch("http://192.168.1.6/graph_image_hubot.php?action=view&local_graph_id=13619&rra_id=5")
    .then(response =>  {
      if (response.ok) {
         return response.buffer();
      }
      throw new Error('Network response was not ok.');
    })
    .then(buffer => {
      const formData = new FormData();
      formData.append( 'media', buffer, {filename: 'bandwidth.png', contentType: 'image/png' } );
      robot.wwork.sendImageMessage(owner, formData);
    });

javascript

上面的程序实际上是从 cacti 服务器拿到一张流量图片,然后 fetch 的结果 anyway,response总是有东西的,都会是成功的,所以我们必须再用 response.ok 来判断,成功就继续得到 buffer 流,最终送到 hubot 中去。三个过程用 then 串了起来,每一步都是成功才会进行下一步。

这样写避免了回调地狱,看起来也比较舒服。

那什么时候用 promise 呢,它是异步的,有大IO读写硬盘、读写网络的时候用,上面是读写网络。下面再来一个读写磁盘的:

const {promise: {readFile, writeFile}} = require('fs');
(async () => {
    let content = await readFile('./data.txt', 'utf8');
    await writeFile('2.txt', content, 'utf8');
    console.log('ok');
})();
javascript

上面的语法是 ES7 的,它更尽了一步,首先声明一个匿名的函数是 async 异步的,然后用await来进行等待,将读和写两个大操作都放到 await 的一步操作中去,这样程序看起来就变成同步的一步步等待了。跟 ES6 的 promise 比起来,更进了一步。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK