I/O Non-Blocking

Escrito em 07 de setembro de 2019 por Lucas Vieira
lucasvieira@protonmail.com

Callbacks

O que são callbacks?

Callback é qualquer código executável passado como argumento para uma função, quando espera-se que este código seja chamado no completamento de outra operação.

Exemplo de código blocking

Arquivo teste.txt

Este é um texto plano.
Se você está vendo, é porque o arquivo foi aberto
com sucesso.

Código de leitura do arquivo

const fs   = require("fs");
const data = fs.readFileSync("teste.txt");

console.log(data.toString());
console.log("Fim do programa");

Exemplo de código non-blocking com callback

Criamos uma callback, que é invocada ao final da leitura do arquivo.

O processo não aguarda o fim da leitura para continuar executando o código.

const fs = require("fs");

fs.readFile("teste.txt", function(err, data) {
    if(err) {
        return console.error(err);
    }
    console.log(data.toString());
});

console.log("Fim do programa");

Eventos

O que é um Evento

Um evento é uma situação específica que ocasiona a chamada de um callback.

A chamada de callbacks mediante certos eventos é gerenciada por um loop de eventos, que faz polling (sondagem) dos mesmos.

A programação baseada em eventos está no cerne da programação reativa.

Exemplo de uso

const events = require("events");

let emitter = new events.EventEmitter();


// Função para lidar com uma conexão.
// Se a conexão ocorreu, emita um sinal de
// recebimento de dados
const connectionHandler = () => {
    console.log("Conectado com sucesso!");
    emitter.emit("data_received");
};

// Ligue o evento de uma conexão ao callback
// que lida com conexões.
emitter.on("connection", connectionHandler);


// Crie o callback de recebimento de dados,
// mas ligue-o imediatamente ao evento
emitter.on("data_received", () => {
    console.log("Dados recebidos com sucesso!");
});


// Emita o evento e encerre o programa.
emitter.emit("connection");
console.log("Fim do Programa.");

Promises

O que é um Promise

Promise (promessa) é uma computação que, por ser feita de forma concorrente, não interrompe o fluxo do programa.

Em algumas linguagens, Promises são conhecidos como Futures.

Um Promise tem três estados:

  • Pending (pendente);
  • Fulfilled (realizada);
  • Rejected (rejeitada).

Exemplo de uso

let request = new Promise(function (resolve, reject) {
    resolve('Ok!');
});

request.then(function (result) {
    console.log("Promise result: " + result);
}, function (error) {
    console.error(error);
});

console.log(request);

Mais um exemplo

let request = new Promise((resolve, reject) => {
    resolve('Ok!');
}).then((res) => console.log(res),
        (err) => console.error(err));

console.log(request);

Async e Await

O que é async e await

Às vezes, o vocabulário para Promises pode ficar muito extenso e ilegível.

Para deixar o código mais sucinto, podemos usar as palavras-chave async e await.

(Mais informações podem ser vistas neste link.)

Exemplo: Arquivos locais com dados de usuários

users.json:

[
    {
        "name": "fulano",
        "age":  "20"
    },
    {
        "name": "ciclano",
        "age":  "21"
    },
    {
        "name": "beltrano",
        "age":  "22"
    }
]

fulano.json:

{
    "full_name":  "Fulano da Silva",
    "blood_type": "A",
    "address":    "Rua dos Bobos",
    "age":        "20"
}

Recuperando dados com Promises

const fs = require('fs');

let regex = /\0/g;

const getObjectFromJSON = filename => {
    let data = fs.readFileSync(filename)
        .toString()
        .replace(regex, "");
    return JSON.parse(data);
};

const getFirstUserData = () => {
    return new Promise((resolve, reject) => {
        resolve(getObjectFromJSON('users.json'));
    }).then(users     => users[0])
      .then(firstUser => getObjectFromJSON(`${firstUser.name}.json`));
}

getFirstUserData().then(data => {
    console.log(data.full_name + " mora em " + data.address);
});
console.log("Fim do programa.");

Tornando o código mais legível

const fs = require('fs');

let regex = /\0/g;

const getObjectFromJSON = async filename => {
    let data = fs.readFileSync(filename)
        .toString()
        .replace(regex, "");
    return JSON.parse(data);
};

const getFirstUserData = async () => {
    const users     = await getObjectFromJSON('users.json');
    const firstUser = users[0];
    const userData  = await getObjectFromJSON(`${firstUser.name}.json`);
    return userData;
}

getFirstUserData().then(data => {
    console.log(data.full_name + " mora em " + data.address);
});
console.log("Fim do programa.");

Exercícios

De volta à página anterior