Promise is a kind of object that when executed, it can be either resolved or rejected.

1
promise.then([onFulfilled], [onRejected])

how to create a Promise

1
2
3
4
new Promise((resolve, reject) => {
})

the argument to initialize a promise is a function with two parameters. resolve, and reject, both are functions.

how to turn a function with callback into a promise ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// function fetchURL(url, callback);
// function parsePage(content, callback);
let fetch = new Promise((resolve, reject) => {
fetchURL(url, (err,result)=>{
if(err){return reject(err);
} else {
return resolve(result);
}
})
})
let parse = new Promise((resolve, reject) => {
parsePage(content, (err,result)=>{
if(err){return reject(err);
} else {
return resolve(result);
}
})
})

then instead of calling

1
2
3
4
5
fetchURL("https://google.com", (err,content)=>{
parsePage(content, (err, result)=>{
//do something here
})
})

we can write something like

1
2
3
4
5
6
fetch("https://google.com").then(
(result)=> parse(result)
).then((result)=>{
//do something with the result;
}
)

then callback hell is turned into promise chain.

promisify

There exists a general way to turn callback-based function into one that returns a promise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module.exports.promisify = function(callbackBasedApi) {
return function promisified() {
const args = [].slice.call(arguments);
return new Promise((resolve, reject) => {
args.push((err, result) => {
if(err) {
return reject(err);
}
if(arguments.length <= 2) {
resolve(result);
} else {
resolve([].slice.call(arguments, 1));
}
});
callbackBasedApi.apply(null, args);
});
}
};

create a function called promisified, which return a promise.

in the promise initialize function, we push a callback function into the arguments into promisified and use the new arguments to call callbackBasedApi, in the callback we pushed into arguments, it use resolve and reject to fullfill a the promise.

Sequential Iteration

1
2
3
4
5
6
7
8
9
10
let tasks = [ /* ... */ ]
let promise = Promise.resolve();
tasks.forEach(task => {
promise = promise.then(() => {
return task();
});
});
promise.then(() => {
//All tasks completed
});

or instead of forEach, use reduce.

1
2
3
4
5
6
7
8
9
10
11
let tasks = [ /* ... */ ]
let promise = tasks.reduce((prev, task) => {
return prev.then(() => {
return task();
});
}, Promise.resolve());
promise.then(() => {
//All tasks completed
});

Both use a Promise.resove() to kick the first iteration.

Parallel execution

1
2
3
4
5
6
let promises = [ /* promises */ ]
Promise.all(promises).then(() => {
//All tasks completed
});