or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-handling.mdindex.mdjavascript-execution.mdruntime-management.md

context-handling.mddocs/

0

# Context Handling

1

2

Work with compiled JavaScript contexts for efficient repeated execution.

3

4

## Overview

5

6

JavaScript contexts allow you to compile JavaScript code once and execute it multiple times efficiently. This is particularly useful when you need to call JavaScript functions repeatedly or maintain JavaScript state between calls.

7

8

## Context Creation

9

10

Contexts are created using the `compile()` function:

11

12

```python

13

import execjs

14

15

# Compile JavaScript code into a context

16

ctx = execjs.compile("""

17

var counter = 0;

18

var utils = {

19

increment: function() { return ++counter; },

20

reset: function() { counter = 0; return counter; },

21

getValue: function() { return counter; }

22

};

23

""")

24

```

25

26

## Context Methods

27

28

### eval()

29

30

Evaluate JavaScript code within the compiled context.

31

32

```python { .api }

33

def eval(self, source):

34

"""

35

Evaluate JavaScript code in the compiled context.

36

37

Args:

38

source (str): JavaScript source code to evaluate

39

40

Returns:

41

any: Result of JavaScript evaluation

42

43

Raises:

44

ProgramError: When JavaScript code contains syntax or runtime errors

45

RuntimeError: When JavaScript runtime engine encounters errors

46

"""

47

```

48

49

### exec_()

50

51

Execute JavaScript code in the context and return stdout output.

52

53

```python { .api }

54

def exec_(self, source):

55

"""

56

Execute JavaScript code in context and return stdout output.

57

58

Args:

59

source (str): JavaScript source code to execute

60

61

Returns:

62

str: Standard output from JavaScript execution

63

64

Raises:

65

ProgramError: When JavaScript code contains syntax or runtime errors

66

RuntimeError: When JavaScript runtime engine encounters errors

67

"""

68

```

69

70

### call()

71

72

Call a JavaScript function by name with arguments.

73

74

```python { .api }

75

def call(self, name, *args):

76

"""

77

Call a JavaScript function by name with arguments.

78

79

Args:

80

name (str): Name of JavaScript function to call

81

*args: Arguments to pass to the function

82

83

Returns:

84

any: Result of function call

85

86

Raises:

87

ProgramError: When function doesn't exist or JavaScript errors occur

88

RuntimeError: When JavaScript runtime engine encounters errors

89

"""

90

```

91

92

### is_available()

93

94

Check if the context is available for execution.

95

96

```python { .api }

97

def is_available(self):

98

"""

99

Check if context is available.

100

101

Returns:

102

bool: True if context is available for execution, False otherwise

103

"""

104

```

105

106

## Usage Examples

107

108

### Function Calls

109

110

```python

111

import execjs

112

113

# Compile JavaScript with functions

114

ctx = execjs.compile("""

115

function add(a, b) {

116

return a + b;

117

}

118

119

function multiply(a, b) {

120

return a * b;

121

}

122

123

var math = {

124

power: function(base, exponent) {

125

return Math.pow(base, exponent);

126

},

127

sqrt: function(n) {

128

return Math.sqrt(n);

129

}

130

};

131

""")

132

133

# Call top-level functions

134

result1 = ctx.call("add", 5, 3) # 8

135

result2 = ctx.call("multiply", 4, 7) # 28

136

137

# Call object methods

138

result3 = ctx.call("math.power", 2, 8) # 256

139

result4 = ctx.call("math.sqrt", 16) # 4

140

```

141

142

### Stateful Contexts

143

144

```python

145

import execjs

146

147

# Create stateful JavaScript context

148

ctx = execjs.compile("""

149

var state = {

150

items: [],

151

counter: 0

152

};

153

154

function addItem(item) {

155

state.items.push(item);

156

state.counter++;

157

return state.counter;

158

}

159

160

function getItems() {

161

return state.items;

162

}

163

164

function getCount() {

165

return state.counter;

166

}

167

168

function reset() {

169

state.items = [];

170

state.counter = 0;

171

return 'reset';

172

}

173

""")

174

175

# Use stateful functions

176

count1 = ctx.call("addItem", "apple") # 1

177

count2 = ctx.call("addItem", "banana") # 2

178

count3 = ctx.call("addItem", "cherry") # 3

179

180

items = ctx.call("getItems") # ['apple', 'banana', 'cherry']

181

total = ctx.call("getCount") # 3

182

183

ctx.call("reset") # 'reset'

184

items_after_reset = ctx.call("getItems") # []

185

```

186

187

### Context Evaluation

188

189

```python

190

import execjs

191

192

# Compile base context

193

ctx = execjs.compile("""

194

var data = {

195

users: [

196

{name: 'Alice', age: 30},

197

{name: 'Bob', age: 25}

198

]

199

};

200

""")

201

202

# Evaluate expressions in context

203

oldest = ctx.eval("data.users.reduce((a, b) => a.age > b.age ? a : b)")

204

# Returns: {'name': 'Alice', 'age': 30}

205

206

names = ctx.eval("data.users.map(u => u.name)")

207

# Returns: ['Alice', 'Bob']

208

209

average_age = ctx.eval("data.users.reduce((sum, u) => sum + u.age, 0) / data.users.length")

210

# Returns: 27.5

211

```

212

213

### Context Execution with Output

214

215

```python

216

import execjs

217

218

# Compile context with logging

219

ctx = execjs.compile("""

220

var log = [];

221

222

function debug(message) {

223

log.push(new Date().toISOString() + ': ' + message);

224

console.log(message);

225

}

226

227

function processData(items) {

228

debug('Starting data processing');

229

var result = items.map(item => item * 2);

230

debug('Processing complete, ' + result.length + ' items processed');

231

return result;

232

}

233

234

function getLogs() {

235

return log;

236

}

237

""")

238

239

# Execute with console output

240

output = ctx.exec_("debug('System initialized')")

241

print(output) # "System initialized\n"

242

243

# Call function that produces output

244

result = ctx.call("processData", [1, 2, 3, 4, 5])

245

# Console output: "Starting data processing" and "Processing complete, 5 items processed"

246

247

# Get internal logs

248

logs = ctx.call("getLogs")

249

print(logs) # Array of timestamped log messages

250

```

251

252

### Error Handling in Contexts

253

254

```python

255

import execjs

256

257

ctx = execjs.compile("""

258

function divide(a, b) {

259

if (b === 0) {

260

throw new Error('Division by zero');

261

}

262

return a / b;

263

}

264

265

function callNonExistentFunction() {

266

return nonExistentFunction();

267

}

268

""")

269

270

# Handle JavaScript errors

271

try:

272

result = ctx.call("divide", 10, 0)

273

except execjs.ProgramError as e:

274

print(f"JavaScript error: {e}") # "JavaScript error: Division by zero"

275

276

try:

277

result = ctx.call("callNonExistentFunction")

278

except execjs.ProgramError as e:

279

print(f"JavaScript error: {e}") # "JavaScript error: nonExistentFunction is not defined"

280

281

# Handle non-existent function calls

282

try:

283

result = ctx.call("nonExistentFunction", 1, 2, 3)

284

except execjs.ProgramError as e:

285

print(f"Function not found: {e}")

286

```

287

288

## Context Lifecycle

289

290

Contexts maintain their state throughout their lifetime:

291

292

```python

293

import execjs

294

295

# Create persistent context

296

ctx = execjs.compile("var x = 1;")

297

298

# State persists between calls

299

ctx.eval("x += 1") # x is now 2

300

ctx.eval("x *= 3") # x is now 6

301

result = ctx.eval("x") # Returns 6

302

303

# Context state is isolated from other contexts

304

ctx2 = execjs.compile("var x = 100;")

305

ctx2_result = ctx2.eval("x") # Returns 100

306

ctx_result = ctx.eval("x") # Still returns 6

307

```

308

309

## Performance Considerations

310

311

Using contexts is more efficient than repeated `eval()` calls when:

312

313

- Calling the same JavaScript functions multiple times

314

- Maintaining state between JavaScript executions

315

- Working with complex JavaScript objects or libraries

316

317

```python

318

import execjs

319

import time

320

321

# Inefficient: recompiling each time

322

start = time.time()

323

for i in range(100):

324

result = execjs.eval(f"Math.pow(2, {i})")

325

slow_time = time.time() - start

326

327

# Efficient: using compiled context

328

ctx = execjs.compile("function power(base, exp) { return Math.pow(base, exp); }")

329

start = time.time()

330

for i in range(100):

331

result = ctx.call("power", 2, i)

332

fast_time = time.time() - start

333

334

print(f"Without context: {slow_time:.3f}s")

335

print(f"With context: {fast_time:.3f}s")

336

```