Asynchronicity
Motivation
function loadScript(src) {
// creates a <script> tag and append it to the page
// this causes the script to load and run when complete
let script = document.createElement('script');
script.src = src;
document.head.append(script);
}
// load and execute the script
loadScript('/my/script.js'); // 5GB script
// this line is evaluated instantly
loadScript('/my/script.js'); // function foo() {...}
foo(); // no such function
Callbacks
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(script);
document.head.append(script);
}loadScript('/my/script.js', () => foo() );
Zweites Script nach erstem laden?
Callbacks in Callbacks
loadScript('/my/script.js', function(script) {
alert(`${script.src} loaded`);
loadScript('/my/script2.js', function(script) {
alert(`${script.src} loaded`);
});
});
loadScript('/my/script.js', function(script) {
loadScript('/my/script2.js', function(script) {
loadScript('/my/script3.js', function(script) {
// everything loaded
});
});
});
Error Handling
function loadScript(src, callback) {
let script = document.createElement('script');
script.src = src;
script.onload = () => callback(null, script);
script.onerror = () => callback(new Error(`Error loading ${src}`));
document.head.append(script);
}
loadScript('/my/script.js', function(error, script) {
if (error) {
// handle error
} else {
// script loaded
}
});
Pyramid of Doom
loadScript('1.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('2.js', function(error, script) {
if (error) {
handleError(error);
} else {
// ...
loadScript('3.js', function(error, script) {
if (error) {
handleError(error);
} else {
// everything loaded
}
});
}
});
}
});
Promises
let promise = new Promise(function(resolve, reject) {
let success = doStuff(); // starts instantly, takes time
if (success)
resolve('done');
else
reject(new Error());
});
let promise = new Promise(function(resolve, reject) {
// after 1s resolve to done
setTimeout(() => resolve('done'), 1000);
});let promise = new Promise(function(resolve, reject) {
// after 1s someting went wrong
setTimeout(() => reject(new Error()), 1000);
});then
promise.then(
function(result) { /* handle successful result */ },
function(error) { /* handle error */ }
);
let promise = new Promise(function(resolve, reject) {
if (Math.random() < .5)
setTimeout(() => resolve('done'), 1000);
else
setTimeout(() => reject(new Error('Whoops!')), 1000);
});
promise.then(
result => console.log(result),
error => console.error(error)
);
catch
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Whoops!')), 1000);
// throw new Error('Whoops!');
});
// promise.then(null, f)
promise.catch(console.info);
finally
try { }
catch { }
finally { }
new Promise((resolve, reject) => {
this.isLoading.set(true); // start loading animation
if (Math.random() < .5)
setTimeout(() => resolve('done'), 1000);
else
setTimeout(() => reject(new Error('Whoops!')), 1000);
})
.finally(() => this.isLoading.set(false)) // return as is
.then( ... );
Initial example
function loadScript(src) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Error loading ${src}`));
document.head.append(script);
});
}let promise = loadScript('/my/script.js');
promise.then(
script => console.info(`${script.src} is loaded!`),
error => console.error(`Error: ${error.message}`)
);
promise.then(script => console.log('Great success'));
Chaining
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
console.log(result); // 1
return result * 2;
}).then(function(result) {
console.log(result); // 2
return result * 2;
}).then(function(result) {
console.log(result); // 4
return result * 2;
});
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
});
promise.then(function(result) {
console.log(result); // 1
return result * 2;
});
promise.then(function(result) {
console.log(result); // 1
return result * 2;
});
promise.then(function(result) {
console.log(result); // 1
return result * 2;
});
async/await
async function f() {
return 42;
// return Promise.resolve(42);
}
async ⟹ Promise
f().then(console.log); // 42
await
function f() {
await 42; // 🚫 Syntax Error
}
async function f() {
await 42; // 👍
}
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // suspends execution
console.log(result);
}
f();
then ⟹ await
promise.then(
result => doStuff(result),
error => handle(error)
);
try {
let result = await promise;
doStuff(result);
} catch(error) {
handle(error);
}
Initial example
async function loadScript(src) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Error loading ${src}`));
document.head.append(script);
});
}async function followup() {
let promise = loadScript('/my/script.js');
try {
let script = await promise;
console.info(`${script.src} is loaded!`);
console.log('Great success');
} catch(error) {
console.error(`Error: ${error.message}`);
}
}