lunes, 25 de octubre de 2021

Javascript Promises

 Javascript Promises

var output = '';
var errorLog = '';

function task(msg, msec){
    output += msg;
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            const error = true;
            !error ? resolve()
                   : reject( 'Error-task-' + msg)
        }, msec);
    });
}

task('task1->', 30)
.then( task('task2->', 10)
       .then(task('task3->', 0)
            .then(display)
            .catch(err => errorLog += err))
       .catch(err => errorLog += err))
.catch(err => errorLog += err)
.finally( () => {display(); displayErrorLog();})

function display(){
  console.log('output: ' + output);
}

function displayErrorLog(){
    console.log('ErrorLog: ' + errorLog);
}

  lets refactor the previos sample of list post, now with promise

const posts = [{title: 'post one', body: 'body of post one'},
              {title: 'post two', body: 'body of post two'}];

function getPosts(){
  setTimeout(() => {
      let output = '';
      posts.forEach( (post, index) => {
        console.log(index + ' ' + post.title );
        output += `<li>${post.title}</li>`;
      });
      document.body.innerHTML = output;
  }, 100);
};

 function createPost(post){
   return new Promise((resolve, reject) => {
       setTimeout(() => {
          posts.push(post);

          const error = false;
          !error ? resolve()
                 : reject('Error: something went wrong');
       }, 200);
   });
};

createPost({title: 'post three', body:'body of post three'})
 .then( getPosts)
 .catch( err => console.log(err));
 

 Another sample, In this case the procedure task put the main procedure of output buffer inside the async function, so the output spected is in disorder defined by the timeout of the procedures because all are executed asynchronously, That´s because the process of buffer output must be out and before the setTimeout (asynchrous process).

var output = '';

function task(msg, msec){
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            output += msg;

            const error = false;
            !error ? resolve()
                   : reject( 'Error - task - ' + msg)
        }, msec);
    });
}

task('task1->', 30)
.then( task2('task2->', 10)
       .then(task('task3->', 50)
            .then(display)))


function display(){
    console.log(output);
}
// output: task2->task1->task3->

 Putting the process of buffer output before the asynchronous process (setTimeout), So the execution order of the task are executed as expected independently of the taken time for each of them.

var output = '';

function task(msg, msec){
    output += msg;
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            const error = false;
            !error ? resolve()
                   : reject( 'Error - task - ' + msg)
        }, msec);
    });
}

task('task1->', 30)
.then( task('task2->', 10)
       .then(task('task3->', 0)
            .then(display)))


function display(){
    console.log(output);
}
// output: task1->task2->task3-

 Adding the catch management for the promises, forcing to fail to see the catch, look the order of the error messages, first the task3 then task2 and finally task1

var output = '';

function task(msg, msec){
    output += msg;
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            const error = true;
            !error ? resolve()
                   : reject( 'Error - task - ' + msg)
        }, msec);
    });
}

task('task1->', 30)
.then( task('task2->', 10)
       .then(task('task3->', 0)
            .then(display)
            .catch(err => console.log(err)))
       .catch(err => console.log(err)))
.catch(err => console.log(err))


function display(){
    console.log(output);
}
// output: Error - task - task3->
//         Error - task - task2->
//         Error - task - task1->
 
Let´s separate the error log buffer display in order to manage the flow. 
The output is ErrorLog with the buffer error empty, why? because the displayErrorLog() is executed asynchronous before all the other process.
 
var output = '';
var errorLog = '';

function task(msg, msec){
    output += msg;
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            const error = true;
            !error ? resolve()
                   : reject( 'Error-task-' + msg)
        }, msec);
    });
}

task('task1->', 30)
.then( task('task2->', 10)
       .then(task('task3->', 0)
            .then(display)
            .catch(err => errorLog += err))
       .catch(err => errorLog += err))
.catch(err => errorLog += err)

displayErrorLog();

function display(){
  console.log('output: ' + output);
}

displayErrorLog();
function displayErrorLog(){
  console.log('ErrorLog: ' + errorLog);
}
// output: ErrorLog:

 To check the error log delay the execution of the displayErrorLog function

... 
task('task1->', 30)
.then( task('task2->', 10)
       .then(task('task3->', 0)
            .then(display)
            .catch(err => errorLog += err))
       .catch(err => errorLog += err))
.catch(err => errorLog += err)

displayErrorLog();

function display(){
  console.log('output: ' + output);
}

displayErrorLog();
function displayErrorLog(){
  setTimeout(()=>{
    console.log('ErrorLog: ' + errorLog);
  }, 40);
}
// output: ErrorLog: Error-task-task3->Error-task-task2->Error-task-task1->

 Or integrate into the build task pattern, this way the displayErrorLog will be secuenciated synchronous into the flow process. notice that .then(displayErrorLog) is not properly used, because .then is executed on resolve situation.

task('task1->', 30)
.then( task('task2->', 10)
       .then(task('task3->', 0)
            .then(display)
            .catch(err => errorLog += err))
       .catch(err => errorLog += err))
.catch(err => errorLog += err)
.then(displayErrorLog)

function display(){
  console.log('output: ' + output);
}

displayErrorLog();
function displayErrorLog(){
    console.log('ErrorLog: ' + errorLog);
}
// output: ErrorLog: Error-task-task3->Error-task-task2->Error-task-task1->

Use displayErrorLog into the last .catch to see all the error buffer log.

... 
task('task1->', 30)
.then( task('task2->', 10)
       .then(task('task3->', 0)
            .then(display)
            .catch(err => errorLog += err))
       .catch(err => errorLog += err))
.catch(err => {errorLog += err; displayErrorLog();})

.finally   To show the buffers at the end of the secuence use .finally

...
task('task1->', 30)
.then( task('task2->', 10)
       .then(task('task3->', 0)
            .then(display)
            .catch(err => errorLog += err))
       .catch(err => errorLog += err))
.catch(err => errorLog += err)
.finally( () => {display(); displayErrorLog();})

// output: output: task1->task2->task3->
//         ErrorLog: Error-task-task3->Error-task-task2->Error-task-task1->

 Sample with callbacks

const userLeft = false
const userWatchingCatMeme = true

function watchTutorialCallback(callback, errorCallback){
    if(userLeft){
        errorCallback({
            name: 'User left',
            message: ':('
        })
    } else if (userWatchingCatMeme) {
        errorCallback({
            name: 'User Watching Cat Meme',
            message: 'message error watching cat meme'
        })
    } else {
        callback('Thanks and Subscribe')
    }
}

watchTutorialCallback((message) =>{
    console.log('Success: ' +  message)
}, (error) => {
    console.log(error.name + ' ' + error.message)
})
 

Success: Thanks and Subscribe

Same but with promise

const userLeft = false
const userWatchingCatMeme = false

function watchTutorialPromise(){
  return new Promise((resolve, reject) => {
    if (userLeft){
        reject({
            name: 'User left',
            message: ':('
        })
    } else if (userWatchingCatMeme) {
        reject({
            name: 'User Watching Cat Meme',
            message: 'message error watching cat meme'
        })
    } else {
        resolve('Thanks and Subscribe')
    }
  });
}

watchTutorialPromise().then((message) => {
    console.log('Success: ' +  message)
}).catch((error) => {
    console.log(error.name + ' ' + error.message)
})

Promise.All

const taskOne = new Promise((resolve,reject) => {
    resolve('task1->')
})

const taskTwo = new Promise((resolve,reject) => {
    resolve('task2->')
})

const taskThree = new Promise((resolve,reject) => {
    resolve('task3->')
})

Promise.all([
    taskOne, taskTwo, taskThree
]).then((message) => {
    console.log( message)
})

//output: Array(3) [ "task1->", "task2->", "task3->" ]
 

 Setting different process time

const taskOne = new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve('task1->')
    }, 2000)
})

const taskTwo = new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve('task2->')
    }, 30)
})

const taskThree = new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve('task3->')
    }, 10)
})

Promise.all([
    taskOne, taskTwo, taskThree
]).then((message) => {
    console.log( message)
})

//output: Array(3) [ "task1->", "task2->", "task3->" ]
 

 Promise.race

const taskOne = new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve('task1->')
    }, 2000)
})

const taskTwo = new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve('task2->')
    }, 30)
})

const taskThree = new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve('task3->')
    }, 10)
})

Promise.race([
    taskOne, taskTwo, taskThree
]).then((message) => {
    console.log( message)
})

//output: task3->

Promise All with fetch json

const promise1 = Promise.resolve("promise1 resolved")
const promise2 = 10;
const promise3 = new Promise((resolve,reject) =>
                              setTimeout(resolve, 100, 'promise3'))
const promise4 = fetch('https://jsonplaceholder.typicode.com/users')
   .then(val => val.json())

Promise.all([ promise1, promise2, promise3, promise4])
.then(value => console.log(value))

Browser Inspector Output
 
Array(4) [ "promise1 resolved", 10, "promise3", (10) […] ]
0: "promise1 resolved"
1: 10
2: "promise3"
3: Array(10) [ {…}, {…}, {…}, … ]
0: Object { id: 1, name: "Leanne Graham", username: "Bret", … }
1: Object { id: 2, name: "Ervin Howell", username: "Antonette", … }
2: Object { id: 3, name: "Clementine Bauch", username: "Samantha", … }
3: Object { id: 4, name: "Patricia Lebsack", username: "Karianne", … }
4: Object { id: 5, name: "Chelsey Dietrich", username: "Kamren", … }
5: Object { id: 6, name: "Mrs. Dennis Schulist", username: "Leopoldo_Corkery", … }
6: Object { id: 7, name: "Kurtis Weissnat", username: "Elwyn.Skiles", … }
7: Object { id: 8, name: "Nicholas Runolfsdottir V", username: "Maxime_Nienow", … }
8: Object { id: 9, name: "Glenna Reichert", username: "Delphine", … }
9: Object { id: 10, name: "Clementina DuBuque", username: "Moriah.Stanton", … }
length: 10
<prototype>: Array []
length: 4
<prototype>: Array []
 

 

 

 

eot

No hay comentarios:

Publicar un comentario