Skip to content

Latest commit

 

History

History
232 lines (203 loc) · 3.92 KB

9.md

File metadata and controls

232 lines (203 loc) · 3.92 KB

Promise Magic

Chain code

function __async(v) {
  return new Promise((resolve, reject) => {
    setTimeout(function() {
      console.log('CB:', v);
      resolve(v);
    }, 500);
  });
}

/*
 bad
 nested .then()
 puzzled
*/
__async(1).then(v => {                                
  console.log(v);
  __async(2)
  .then(vv => {
    console.log(vv);
    __async(3).then(vvv => {
      console.log(vvv);
    })
  })
});

/*
 good
 chain code
 readable
*/
__async(1).then(v => {
  console.log(v);
  return __async(2);
}).then(v => {
  console.log(v);
  return __async(3);
}).then(v => {
  console.log(v);
});

Queue operation

function queueOp() {                                    
  let qLocks = {};

  function scheduleNextOp(qId) {
    let opLock = qLocks[qId];
    if (!opLock) {
      return;
    }
    if (opLock.next.length === 0) {
      delete qLocks[qId];
      return;
    }
    let n = opLock.next.shift();
    n.resolve(null);
  }

  /*
   @param {String} qId, unique
   @param {Function} op, function which returns a Promise
  */
  return function(qId, op) {
    return new Promise((resolve, reject) => {
      let opLock = qLocks[qId];
      if (!opLock) {
        qLocks[qId] = opLock = {
          next: []
        }
        resolve();
      } else {
        opLock.next.push({resolve, reject});
      }
    }).then(() => {
      return op();
    }).then((v) => {
      scheduleNextOp(qId);
      return v;
    }).catch(e => {
      scheduleNextOp(qId);
      throw e;
    });
  }
}

test:

function __async(v, t) {
  return new Promise((resolve, reject) => {
    console.log(Date.now(), 'Start', v);
    setTimeout(() => {
      console.log(Date.now(), 'End', v);
      resolve(v);
    }, t);
  });
}

try {
  let myQueueOp = queueOp();
  myQueueOp('test', () => {
    return __async(1111, 1000);
  });
  myQueueOp('test', () => {
    return __async(2222, 2000);
  });
  myQueueOp('test', () => {
    return __async(3333, 1000);
  });
} catch (e) {
  console.error(e);
}                                                   

output:

1480915146233 'Start' 1111
1480915147239 'End' 1111
1480915147242 'Start' 2222
1480915149245 'End' 2222
1480915149246 'Start' 3333
1480915150247 'End' 3333

Batch async

/*
 @param {Number} step
 @param {Array} ps, Array of function which returns a Promise
*/
function batchAsync(step, ps) {                                          
  let result = [];
  return function batch(ps) {
    if (ps.length > step) {
      return Promise.all(ps.slice(0, step).map((f)=>f())).then(vs => {
        console.log('Done:', vs);
        result = result.concat(vs);
        return batch(ps.slice(step, ps.length));
      });
    } else {
      return Promise.all(ps.map((f)=>f())).then(vs => {
        result = result.concat(vs);
        console.log('Done:', vs);
        return Promise.resolve(result);
      });
    }
  }
}

test:

function __batch(v) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('CB:', v)
      resolve(v);
    }, 500)
  });
}

let myBatch = batchAsync(5);
let ps = [];

for (let i = 0; i < 21; i++) {
  ps.push(function() {
    return __batch(i);
  });
}

myBatch(ps).then(v => {
  console.log('ALL DONE:', v);
}).catch(e => {
  console.error('Batch error:', e)
});

output:

CB: 0
CB: 1
CB: 2
CB: 3
CB: 4
Done: [ 0, 1, 2, 3, 4 ]
CB: 5
CB: 6
CB: 7
CB: 8
CB: 9
Done: [ 5, 6, 7, 8, 9 ]
CB: 10
CB: 11
CB: 12
CB: 13
CB: 14
Done: [ 10, 11, 12, 13, 14 ]
CB: 15
CB: 16
CB: 17
CB: 18
CB: 19
Done: [ 15, 16, 17, 18, 19 ]
CB: 20
Done: [ 20 ]
ALL DONE: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ]