How to Survive in Async Hell
Song YANG
var x = getX(); // 1
var y = getY(); // 5
var sum = x + y;
console.log(sum); // 6
$.ajaxSetup({
async: false,
timeout: 1000
})
var foo = $.get('//google.com')
var bar = $.get('//stackoverflow.com')
var qux = $.get('//bing.com')
console.log(foo)
console.log(bar)
console.log(qux)
function B(callback) {
// Do operation that takes some time
callback('Done!');
}
function A(message) {
console.log(message);
}
// Execute `B` with `A` as a callback
B(A);
fs.readFile('/etc/passwd', (err, data) => {
if (err) throw err;
console.log(data);
});
getData(function(a){
getMoreData(a, function(b){
getMoreData(b, function(c){
getMoreData(c, function(d){
getMoreData(d, function(e){
...
});
});
});
});
});
function printRandomId(callback) {
setTimeout(() => {
callback(Math.random())
callback(Math.random())
}, 0)
}
printRandomId((val) => {
console.log(val)
})
// print twice
function getY () {
var innerY
setTimeout(function () {
innerY = 'Y'
}, 0)
return innerY
}
var y = getY();
console.log(y);
// undefined
function throwUncaughtError () {
try {
setTimeout(function() {
throw new Error('Whoops!');
}, 1000);
}
catch (e) {
alert("You won't see this!");
}
}
var somePromise = new Promise(function(resolve, reject) {
// 异步处理
// 处理结束后、调用resolve 或 reject
setTimeout(function() {
resolve('Value Resolved')
}, 1000);
});
new Promise(function(resolve){
resolve(42);
});
// Returns a Promise object that is resolved with the given value.
Promise.resolve(42)
promise.then(onFulfilled, onRejected)
somePromise().then(function () {
// I'm inside a then() function!
});
Every promise gives you a then() method,
or catch(), which is just sugar for then(null, ...)
getUser('userID')
.then(onFulfilled, onRejected)
getUser('userID')
.then(function(userData) {
if(userData) return 'Success!'
else throw new Error('No user data was found...')
// your app logic error, always throw with an Error...
}, function(reason){
//handle DB errors...
})
always return or throw from inside a then() function
getUser('userID')
.then(null, onRejected)
getUser('userID')
.catch(onRejected)
getUser('userID')
.then(onFulfillOne, onRejectOne)
.then(onFulfillTwo)
.then(null, onRejectTwo)
getUser('userID')
.then(updateOtherthing)
.then(deleteStuff)
.then(logResults)
.catch(handleError)
" a promise handler always return another Promise"
Therefore it can be chained to other Promises
function taskA() {
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}
function finalTask() {
console.log("Final Task");
}
var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.catch(onRejected)
.then(finalTask);
// case 1
login().then(function () {
return getUserInfo()
})
.then(finalHandler)
.catch(errorHandler)
// case 2
login().then(function (token) {
getUserInfo(token)
})
.then(finalHandler)
.catch(errorHandler)
// case 3
login().then(getUserInfo())
.then(finalHandler)
.catch(errorHandler)
// case 4
login().then(getUserInfo)
.then(finalHandler)
.catch(errorHandler)
login().then((token) => {
return getUserInfo(token)
})
.then(finalHandler)
.catch(errorHandler)
login
|-----------|
getUserInfo(token)
|-----------|
finalHandler(userInfo)
|------------------|
login().then(function () {
return getUserInfo()
})
.then(finalHandler)
.catch(errorHandler)
login
|-----------|
getUserInfo(undefined)
|-----------|
errorHandler(rejectedUserInfo)
|------------------|
login().then(function (token) {
getUserInfo(token)
})
.then(finalHandler)
.catch(errorHandler)
login
|-----------|
getUserInfo(token)
|-----------|
finalHandler(undefined)
|------------------|
login().then(getUserInfo())
.then(finalHandler)
.catch(errorHandler)
login
|-----------|
getUserInfo(undefined)
|---------------------|
finalHandler(token)
|------------------|
login().then(getUserInfo)
.then(finalHandler)
.catch(errorHandler)
login
|-----------|
getUserInfo(token)
|-----------------|
finalHandler(userInfo)
|------------------|
Defined in ES6
Other Libraries
function* foo () {
var index = 0;
while (index < 2) {
yield index++;
}
}
var bar = foo();
console.log(bar.next()); // { value: 0, done: false }
console.log(bar.next()); // { value: 1, done: false }
console.log(bar.next()); // { value: undefined, done: true }
co(function *(){
// resolve multiple promises in parallel
var a = Promise.resolve(1);
var b = Promise.resolve(2);
var c = Promise.resolve(3);
var res = yield [a, b, c];
console.log(res);
// => [1, 2, 3]
}).catch(onerror);
var koa = require('koa');
var app = koa();
// logger
app.use(function *(next){
var start = new Date;
yield next;
var ms = new Date - start;
console.log('%s %s - %s', this.method, this.url, ms);
});
// response
app.use(function *(){
this.body = 'Hello World';
});
app.listen(3000);
async function foo () {
var message = await operationTakesTime();
console.log(message);
}
function promisingOperation() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if( Math.round(Math.random()) )
resolve('Success!');
else
reject('Failure!');
}, 1000);
})
}
async function foo() {
var message = await promisingOperation();
console.log(message);
}
window.foo = foo
// Koa application is now a class and requires the new operator.
const app = new Koa();
// uses async arrow functions
app.use(async (ctx, next) => {
try {
await next(); // next is now a function
} catch (err) {
ctx.body = { message: err.message };
ctx.status = err.status || 500;
}
});
app.use(async ctx => {
const user = await User.getById(ctx.session.userid); // await instead of yield
ctx.body = user; // ctx instead of this
});